From 5220d5fe5780755fc02c01287e8b63242529a1ef Mon Sep 17 00:00:00 2001 From: Larry Claman <25161683+larryclaman@users.noreply.github.com> Date: Wed, 15 Mar 2023 13:22:35 -0400 Subject: [PATCH 01/35] Update README.md --- 045-InfraAsCode-Bicep/README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/045-InfraAsCode-Bicep/README.md b/045-InfraAsCode-Bicep/README.md index 84d83f1fa0..0a7c09ef66 100644 --- a/045-InfraAsCode-Bicep/README.md +++ b/045-InfraAsCode-Bicep/README.md @@ -82,3 +82,6 @@ You will want to prepare your machine with the following to help complete the Ch - Mark Garner - Jesse Mrasek - Andy Huang +- Larry Claman +- PJ Johnson +- Sven Aelterman From 01811963c75f5fdd405c821b3c7895fc08e6c82f Mon Sep 17 00:00:00 2001 From: Larry Claman <25161683+larryclaman@users.noreply.github.com> Date: Mon, 8 May 2023 14:42:08 -0400 Subject: [PATCH 02/35] rewrite terraform hack --- .../.devcontainer/devcontainer.json | 16 ++ 012-InfraAsCode-Terraform/.gitignore | 3 + 012-InfraAsCode-Terraform/Coach/README.md | 10 ++ .../Coach/Solution-00.md | 129 ++++++++++++++ .../Coach/Solution-01.md | 9 + .../Coach/Solution-02.md | 8 + .../Coach/Solution-03.md | 7 + .../Coach/Solution-04.md | 11 ++ .../Coach/Solution-05.md | 7 + .../Coach/Solution-06.md | 11 ++ .../Coach/Solution-07.md | 7 + .../Coach/Solution-08.md | 8 + .../Challenge 1 - resource group.tf | 11 -- .../Challenge 2/Challenge 2 - vnet.tf | 28 --- .../Challenge 3 - vnet with nsg.tf | 50 ------ .../Challenge 4/Challenge 4 - variables.tf | 36 ---- .../Challenge 4 - variables.tfvars | 35 ---- ...allenge 4 - vnet with nsg and variables.tf | 50 ------ .../Challenge 5 - create Ubuntu VM.tf | 141 --------------- .../Challenge 5/Challenge 5 - variables.tf | 78 --------- .../Challenge 5 - variables.tfvars | 82 --------- .../plugins/windows_amd64/lock.json | 4 - ...enge 6 - Create Ubuntu VM with Packer.json | 35 ---- ...lenge 6 - Create Ubuntu VM. with Packer.tf | 160 ----------------- .../Challenge 6/Challenge 6 - variables.tf | 78 --------- .../Challenge 6 - variables.tfvars | 87 ---------- .../Terraform-Challenge-01/challenge-01.sh | 34 ++++ .../Terraform-Challenge-01/main01.tf | 50 ++++++ .../Terraform-Challenge-01/terraform.tfvars | 3 + .../Terraform-Challenge-02/challenge-02.sh | 9 + .../Terraform-Challenge-02/main02.tf | 26 +++ .../Terraform-Challenge-02/outputs.tf | 11 ++ .../Terraform-Challenge-02/terraform.tf | 23 +++ .../Terraform-Challenge-02/terraform.tfvars | 4 + .../Terraform-Challenge-02/variables.tf | 21 +++ .../Terraform-Challenge-03/challenge-03.sh | 9 + .../Terraform-Challenge-03/main03.tf | 45 +++++ .../Terraform-Challenge-03/terraform.tf | 23 +++ .../Terraform-Challenge-03/terraform.tfvars | 4 + .../Terraform-Challenge-03/variables.tf | 21 +++ .../Terraform-Challenge-04/challenge-04.sh | 10 ++ .../Solutions/Terraform-Challenge-04/kv.tf | 56 ++++++ .../Terraform-Challenge-04/main04.tf | 46 +++++ .../Terraform-Challenge-04/terraform.tf | 28 +++ .../Terraform-Challenge-04/terraform.tfvars | 4 + .../Terraform-Challenge-04/variables.tf | 25 +++ .../Terraform-Challenge-05/.gitignore | 1 + .../Terraform-Challenge-05/challenge-05.sh | 9 + .../Solutions/Terraform-Challenge-05/kv.tf | 56 ++++++ .../Terraform-Challenge-05/main05.tf | 46 +++++ .../Terraform-Challenge-05/terraform.tf | 28 +++ .../Terraform-Challenge-05/terraform.tfvars | 4 + .../Terraform-Challenge-05/variables.tf | 30 ++++ .../Solutions/Terraform-Challenge-05/vm.tf | 138 +++++++++++++++ .../Terraform-Challenge-06/.gitignore | 1 + .../Terraform-Challenge-06/challenge-06.sh | 9 + .../Solutions/Terraform-Challenge-06/kv.tf | 56 ++++++ .../Terraform-Challenge-06/main06.tf | 58 +++++++ .../modules/network/main.tf | 49 ++++++ .../modules/network/output.tf | 3 + .../modules/network/variables.tf | 18 ++ .../Terraform-Challenge-06/modules/vm/main.tf | 64 +++++++ .../modules/vm/output.tf | 4 + .../modules/vm/variables.tf | 23 +++ .../Terraform-Challenge-06/output.tf | 3 + .../Terraform-Challenge-06/terraform.tf | 28 +++ .../Terraform-Challenge-06/terraform.tfvars | 4 + .../Terraform-Challenge-06/variables.tf | 30 ++++ .../Terraform-Challenge-07/challenge-07.sh | 9 + .../Terraform-Challenge-07/disabled/kv.tf | 56 ++++++ .../Terraform-Challenge-07/main07.tf | 83 +++++++++ .../Terraform-Challenge-07/output.tf | 0 .../Terraform-Challenge-07/terraform.tf | 28 +++ .../Terraform-Challenge-07/terraform.tfvars | 4 + .../Terraform-Challenge-07/variables.tf | 37 ++++ .../acr/challenge-08-acr.sh | 9 + .../Terraform-Challenge-08/acr/main08acr.tf | 35 ++++ .../Terraform-Challenge-08/acr/terraform.tf | 32 ++++ .../acr/terraform.tfvars | 3 + .../Terraform-Challenge-08/acr/variables.tf | 14 ++ .../Terraform-Challenge-08/challenge-08.sh | 9 + .../Terraform-Challenge-08/main08.tf | 164 ++++++++++++++++++ .../Terraform-Challenge-08/output.tf | 0 .../Terraform-Challenge-08/terraform.tf | 28 +++ .../Terraform-Challenge-08/terraform.tfvars | 2 + .../Terraform-Challenge-08/variables.tf | 22 +++ .../Terraform-Challenge-09-wip/appgw.tf | 140 +++++++++++++++ .../challenge-09.sh | 9 + .../Terraform-Challenge-09-wip/main09.tf | 164 ++++++++++++++++++ .../Terraform-Challenge-09-wip/output.tf | 0 .../Terraform-Challenge-09-wip/terraform.tf | 28 +++ .../terraform.tfvars | 2 + .../Terraform-Challenge-09-wip/variables.tf | 22 +++ .../Student/Prerequisites/set_terraform.sh | 7 - .../Student/Terraform-Challenge-00.md | 57 ++++++ .../Student/Terraform-Challenge-01.md | 46 +++++ .../Student/Terraform-Challenge-02.md | 41 +++++ .../Student/Terraform-Challenge-03.md | 24 +++ .../Student/Terraform-Challenge-04.md | 34 ++++ .../Student/Terraform-Challenge-05.md | 41 +++++ .../Student/Terraform-Challenge-06.md | 39 +++++ .../Student/Terraform-Challenge-07.md | 27 +++ .../Student/Terraform-Challenge-08.md | 91 ++++++++++ .../Student/prerequisite.md | 49 ------ 012-InfraAsCode-Terraform/Student/readme.md | 61 ------- .../modules/importimage/import.tf | 36 ++++ 012-InfraAsCode-Terraform/readme.md | 86 ++++----- 107 files changed, 2723 insertions(+), 1031 deletions(-) create mode 100644 012-InfraAsCode-Terraform/.devcontainer/devcontainer.json create mode 100644 012-InfraAsCode-Terraform/.gitignore create mode 100644 012-InfraAsCode-Terraform/Coach/README.md create mode 100644 012-InfraAsCode-Terraform/Coach/Solution-00.md create mode 100644 012-InfraAsCode-Terraform/Coach/Solution-01.md create mode 100644 012-InfraAsCode-Terraform/Coach/Solution-02.md create mode 100644 012-InfraAsCode-Terraform/Coach/Solution-03.md create mode 100644 012-InfraAsCode-Terraform/Coach/Solution-04.md create mode 100644 012-InfraAsCode-Terraform/Coach/Solution-05.md create mode 100644 012-InfraAsCode-Terraform/Coach/Solution-06.md create mode 100644 012-InfraAsCode-Terraform/Coach/Solution-07.md create mode 100644 012-InfraAsCode-Terraform/Coach/Solution-08.md delete mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Challenge 1/Challenge 1 - resource group.tf delete mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Challenge 2/Challenge 2 - vnet.tf delete mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Challenge 3/Challenge 3 - vnet with nsg.tf delete mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Challenge 4/Challenge 4 - variables.tf delete mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Challenge 4/Challenge 4 - variables.tfvars delete mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Challenge 4/Challenge 4 - vnet with nsg and variables.tf delete mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Challenge 5/Challenge 5 - create Ubuntu VM.tf delete mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Challenge 5/Challenge 5 - variables.tf delete mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Challenge 5/Challenge 5 - variables.tfvars delete mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Challenge 6/.terraform/plugins/windows_amd64/lock.json delete mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Challenge 6/Challenge 6 - Create Ubuntu VM with Packer.json delete mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Challenge 6/Challenge 6 - Create Ubuntu VM. with Packer.tf delete mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Challenge 6/Challenge 6 - variables.tf delete mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Challenge 6/Challenge 6 - variables.tfvars create mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-01/challenge-01.sh create mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-01/main01.tf create mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-01/terraform.tfvars create mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-02/challenge-02.sh create mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-02/main02.tf create mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-02/outputs.tf create mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-02/terraform.tf create mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-02/terraform.tfvars create mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-02/variables.tf create mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-03/challenge-03.sh create mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-03/main03.tf create mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-03/terraform.tf create mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-03/terraform.tfvars create mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-03/variables.tf create mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-04/challenge-04.sh create mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-04/kv.tf create mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-04/main04.tf create mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-04/terraform.tf create mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-04/terraform.tfvars create mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-04/variables.tf create mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-05/.gitignore create mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-05/challenge-05.sh create mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-05/kv.tf create mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-05/main05.tf create mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-05/terraform.tf create mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-05/terraform.tfvars create mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-05/variables.tf create mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-05/vm.tf create mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-06/.gitignore create mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-06/challenge-06.sh create mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-06/kv.tf create mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-06/main06.tf create mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-06/modules/network/main.tf create mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-06/modules/network/output.tf create mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-06/modules/network/variables.tf create mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-06/modules/vm/main.tf create mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-06/modules/vm/output.tf create mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-06/modules/vm/variables.tf create mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-06/output.tf create mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-06/terraform.tf create mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-06/terraform.tfvars create mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-06/variables.tf create mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-07/challenge-07.sh create mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-07/disabled/kv.tf create mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-07/main07.tf create mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-07/output.tf create mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-07/terraform.tf create mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-07/terraform.tfvars create mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-07/variables.tf create mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-08/acr/challenge-08-acr.sh create mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-08/acr/main08acr.tf create mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-08/acr/terraform.tf create mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-08/acr/terraform.tfvars create mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-08/acr/variables.tf create mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-08/challenge-08.sh create mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-08/main08.tf create mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-08/output.tf create mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-08/terraform.tf create mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-08/terraform.tfvars create mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-08/variables.tf create mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-09-wip/appgw.tf create mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-09-wip/challenge-09.sh create mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-09-wip/main09.tf create mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-09-wip/output.tf create mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-09-wip/terraform.tf create mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-09-wip/terraform.tfvars create mode 100644 012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-09-wip/variables.tf delete mode 100644 012-InfraAsCode-Terraform/Student/Prerequisites/set_terraform.sh create mode 100644 012-InfraAsCode-Terraform/Student/Terraform-Challenge-00.md create mode 100644 012-InfraAsCode-Terraform/Student/Terraform-Challenge-01.md create mode 100644 012-InfraAsCode-Terraform/Student/Terraform-Challenge-02.md create mode 100644 012-InfraAsCode-Terraform/Student/Terraform-Challenge-03.md create mode 100644 012-InfraAsCode-Terraform/Student/Terraform-Challenge-04.md create mode 100644 012-InfraAsCode-Terraform/Student/Terraform-Challenge-05.md create mode 100644 012-InfraAsCode-Terraform/Student/Terraform-Challenge-06.md create mode 100644 012-InfraAsCode-Terraform/Student/Terraform-Challenge-07.md create mode 100644 012-InfraAsCode-Terraform/Student/Terraform-Challenge-08.md delete mode 100644 012-InfraAsCode-Terraform/Student/prerequisite.md delete mode 100644 012-InfraAsCode-Terraform/Student/readme.md create mode 100644 012-InfraAsCode-Terraform/modules/importimage/import.tf diff --git a/012-InfraAsCode-Terraform/.devcontainer/devcontainer.json b/012-InfraAsCode-Terraform/.devcontainer/devcontainer.json new file mode 100644 index 0000000000..051869b515 --- /dev/null +++ b/012-InfraAsCode-Terraform/.devcontainer/devcontainer.json @@ -0,0 +1,16 @@ +{ + "image": "mcr.microsoft.com/devcontainers/universal:2", + "features": { + "ghcr.io/devcontainers/features/azure-cli:1": { + "version": "latest" + }, + "ghcr.io/devcontainers/features/terraform:1": { + "version": "latest", + "tflint": "latest", + "terragrunt": "latest" + }, + "ghcr.io/devcontainers-contrib/features/terraform-ls-asdf:2": { + "version": "latest" + } + } +} \ No newline at end of file diff --git a/012-InfraAsCode-Terraform/.gitignore b/012-InfraAsCode-Terraform/.gitignore new file mode 100644 index 0000000000..55929b52f7 --- /dev/null +++ b/012-InfraAsCode-Terraform/.gitignore @@ -0,0 +1,3 @@ +.terraform +.terraform.lock.hcl +*.tfstate \ No newline at end of file diff --git a/012-InfraAsCode-Terraform/Coach/README.md b/012-InfraAsCode-Terraform/Coach/README.md new file mode 100644 index 0000000000..7a61570128 --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/README.md @@ -0,0 +1,10 @@ +# What The Hack - Infrastructure As Code: Terraform - Coach's Guide + +## Introduction +Welcome to the coach's guide for the Infrastructure As Code: Terraform What The Hack. Here you will find links to specific guidance for coaches for each of the challenges. + +Also remember that this hack includes a optional [lecture presentation](tbd) that features short presentations to introduce key topics associated with each challenge. It is recommended that the host present each short presentation before attendees kick off that challenge. + +**NOTE:** If you are a Hackathon participant, this is the answer guide. Don't cheat yourself by looking at these during the hack! Go learn something. :) + +## Coach's Guides diff --git a/012-InfraAsCode-Terraform/Coach/Solution-00.md b/012-InfraAsCode-Terraform/Coach/Solution-00.md new file mode 100644 index 0000000000..85d820c193 --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solution-00.md @@ -0,0 +1,129 @@ +# Challenge 0: Pre-requisites - Ready, Set, Go! - Coach's Guide + +**[Home](./README.md)** - [Next Challenge>](./Solution-01.md) + +## Notes & Guidance + +Below are more details on the pre-requisites which you may wish to share with students if they have questions about the details of any one of these. + +## Azure Subscription + +You will need an Azure subscription to complete this hackathon. If you don't have one... + +[Sign Up for Azure HERE](https://azure.microsoft.com/en-us/free/) + +Our goal in the hackathon is limiting the cost of using Azure services. + +If you've never used Azure, you will get: +- $200 free credits for use for up to 30 days +- 12 months of popular free services (includes storage, Linux VMs) +- Then there are services that are free up to a certain quota + +Details can be found here on [free services](https://azure.microsoft.com/en-us/free/). + +If you have used Azure before, we will still try to limit cost of services by suspending, shutting down services, or destroy services before end of the hackathon. You will still be able to use the free services (up to their quotas) like App Service, or Functions. + +## Windows Subsystem for Linux + +The Windows Subsystem for Linux (WSL) lets developers run Linux environments -- including most command-line tools, utilities, and applications -- directly on Windows, unmodified, without the overhead of a virtual machine. + +WSL is an essential tool Azure admins should have on their workstations if they are running Windows! If you work with Linux servers in Azure (or anywhere), having access to WSL enables you to easily connect to them and use all the tools you're used to. + +[Install the Windows Subsystem for Linux](https://docs.microsoft.com/en-us/windows/wsl/install-win10) + +If you drive a Mac or Linux workstation, then you've already got Terminal access, carry on! :) + +## Managing Cloud Resources + +We can manage cloud resources via the following ways: + +- Web Interface/Dashboard + - [Azure Portal](https://portal.azure.com/) +- CLI + - [Azure CLI](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli) + - [Azure PowerShell Cmdlets](https://docs.microsoft.com/en-us/powershell/azure/install-azurerm-ps) +- CLI within Web Interface + - [Azure Cloud Shell (Bash)](https://shell.azure.com/bash) + - [Azure Cloud Shell (PowerShell)](https://shell.azure.com/powershell) + + +### Azure Portal + +Build, manage, and monitor everything from simple web apps to complex cloud applications in a single, unified console. + +Manage your resources via a web interface (i.e. GUI) at [https://portal.azure.com/](https://portal.azure.com/) + +The Azure Portal is a great tool for quick prototyping, proof of concepts, and testing things out in Azure by deploying resources manually. However, when deploying production resources to Azure, it is highly recommended that you an automation tool, templates, or scripts instead of the portal. + +**Note:** That's why you're participating in this "Infrastructure as Code" hackathon! + +### Azure CLI + +The Azure CLI is a cross-platform command-line tool providing a great experience for managing Azure resources. The CLI is designed to make scripting easy, flexibly query data, support long-running operations as non-blocking processes, and more. It is available on Windows, Mac, and Linux. + +The Azure CLI will be the preferred (and supported) approach for this event, so please install the Azure CLI on your workstation. If you are not able to install the Azure CLI, or are using a workstation that is not your own, you can use the Azure CLI in the browser via the Azure Cloud Shell from the Azure Portal. + +For Windows users, see the note below about how & where to install the Azure CLI! + + +- [Install on Windows](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli-windows?view=azure-cli-latest) +- [Install on macOS](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli-macos?view=azure-cli-latest) +- Install on Linux or Windows Subsystem for Linux (WSL) + - [Install with apt on Debian or Ubuntu](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli-apt?view=azure-cli-latest) + - [Install with yum on RHEL, Fedora, or CentOS](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli-yum?view=azure-cli-latest) + - [Install from script](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli-linux?view=azure-cli-latest) +- [Run in Docker container](https://docs.microsoft.com/en-us/cli/azure/run-azure-cli-docker?view=azure-cli-latest) + +#### Note for Windows Users + +The Azure CLI can be installed locally on Windows. If you do this, you will access and use the Azure CLI from the Windows Command Prompt or PowerShell Console. + +While majority of the documentation should work fine locally on Windows, as you search the web for examples of how to use the Azure CLI, the examples frequently show Azure CLI commands used in Bash shell scripts. Bash shell scripts will not run in the Windows Command Prompt or PowerShell Console. + +For this reason, we recommend using [Windows Subsystem for Linux](https://docs.microsoft.com/en-us/windows/wsl/install-win10) for interacting with the Azure CLI. This means you should install the Azure CLI within your WSL environment by following the instructions for the Linux distro you are using. + +Alternatively, you can use the [Azure Cloud Shell](https://shell.azure.com/bash). This is discussed shortly in the next section. + +### Azure PowerShell CmdLets + +Azure PowerShell provides a set of cmdlets that use the Azure Resource Manager model for managing your Azure resources. + +[Install the Azure PowerShell Cmdlets](https://docs.microsoft.com/en-us/powershell/azure/install-azurerm-ps) + +The Azure PowerShell Cmdlets are functionally equivalent to the Azure CLI and can be used to complete all of the challenges instead of the Azure CLI. However, the Azure PowerShell Cmdlets are required for the PowerShell DSC challenges. + + +### Azure Cloud Shell + +The Azure Cloud Shell is a free interactive Bash or PowerShell shell that you can use to run the Azure CLI or PowerShell Cmdlets needed to complete the hackathon challenges. It has common Azure tools pre-installed and configured to use with your account. Just click the **Copy** button to copy the code, paste it into the Cloud Shell, and then press enter to run it. There are a few ways to launch the Cloud Shell: + +| | | +|-----------------------------------------------|---| +| Click **Try It** in the upper right corner of a code block. | ![Cloud Shell in this article](https://github.com/MicrosoftDocs/azure-docs/raw/master/includes/media/cloud-shell-try-it/cli-try-it.png) | +| Open Cloud Shell in your browser. | [![https://shell.azure.com/bash](https://github.com/MicrosoftDocs/azure-docs/raw/master/includes/media/cloud-shell-try-it/launchcloudshell.png)](https://shell.azure.com/bash) | +| Click the **Cloud Shell** button on the menu in the upper right of the [Azure portal](https://portal.azure.com). | ![Cloud Shell in the portal](https://github.com/MicrosoftDocs/azure-docs/raw/master/includes/media/cloud-shell-try-it/cloud-shell-menu.png) | +| | | + + +**Note:** If you use the Azure CLI or PowerShell from the Azure Cloud Shell, you will need to copy the template files you will be creating and editing on your workstation during the hackathon to the Cloud Shell environment. + + +## Visual Studio Code + +Visual Studio Code is a lightweight but powerful source code editor which runs on your desktop and is available for Windows, macOS and Linux. It comes with built-in support for JavaScript, TypeScript and Node.js and has a rich ecosystem of extensions for other languages (such as C++, C#, Java, Python, PHP, Go) and runtimes (such as .NET and Unity). + +[**Install Visual Studio Code**](https://code.visualstudio.com/) + +VS Code runs on Windows, Mac, and Linux. Yes, Mac AND Linux! It's a quick install, NOT a 2 hour install like its namesake full-fledged IDE tool on Windows. + +### Visual Studio Code plugins for Bicep + +VS Code is lightweight because there is an ecosystem of plugins that help provide support for many different programming languages and file types. There are two plugins available which we recommend for creating and editing ARM templates in VS Code. We will be using these during the hackathon. + +[**Bicep Plugin**](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-bicep) + +This extension provides language support for Bicep and its language expressions. It adds syntax color-coding support and intellisense for editing Bicep file in VS Code. + +[**Bicep CLI**](https://github.com/Azure/bicep/blob/main/docs/installing.md) + + Compiles Bicep files into ARM templates. Cross-platform. \ No newline at end of file diff --git a/012-InfraAsCode-Terraform/Coach/Solution-01.md b/012-InfraAsCode-Terraform/Coach/Solution-01.md new file mode 100644 index 0000000000..263061e6c4 --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solution-01.md @@ -0,0 +1,9 @@ +# Challenge 1: Basic Terraform - Coach's Guide + +[< Previous Challenge](./Solution-00.md) - **[Home](./README.md)** - [Next Challenge>](./Solution-02.md) + +## Notes & Guidance + +This is the "Hello World" challenge. The goal is to deploy an Azure Storage Account to a targeted resource group. This storage account will be accessed again in Challenge 2. + +If you are self-hosting, recommend to prefix your resources with your initials to avoid conflicts. diff --git a/012-InfraAsCode-Terraform/Coach/Solution-02.md b/012-InfraAsCode-Terraform/Coach/Solution-02.md new file mode 100644 index 0000000000..15f15d08b5 --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solution-02.md @@ -0,0 +1,8 @@ +# Challenge 2: Terraform Expressions and Referencing Resources - Coach's Guide + +[< Previous Challenge](./Solution-01.md) - **[Home](./README.md)** - [Next Challenge >](./Solution-03.md) + +## Notes & Guidance + +Please review the solution in the Solutions folder. + diff --git a/012-InfraAsCode-Terraform/Coach/Solution-03.md b/012-InfraAsCode-Terraform/Coach/Solution-03.md new file mode 100644 index 0000000000..e171c29d98 --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solution-03.md @@ -0,0 +1,7 @@ +# Challenge 3: Advanced Resource Declarations - Coach's Guide + +[< Previous Challenge](./Solution-02.md) - **[Home](./README.md)** - [Next Challenge>](./Solution-04.md) + +## Notes & Guidance + +Please review the solution in the Solutions folder. \ No newline at end of file diff --git a/012-InfraAsCode-Terraform/Coach/Solution-04.md b/012-InfraAsCode-Terraform/Coach/Solution-04.md new file mode 100644 index 0000000000..85bdb0b916 --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solution-04.md @@ -0,0 +1,11 @@ +# Challenge 4: Secret Values with Azure Key Vault - Coach's Guide + +[< Previous Challenge](./Solution-03.md) - **[Home](./README.md)** - [Next Challenge >](./Solution-05.md) + +## Notes & Guidance + +This challenge, while conceptually straightforward, has a number of "gotchas" that can complicate getting it working. + ++ Make sure you are using the latest version of the azurerm provider (eg >= 3.52.0). Earlier versions had problems with timing out when configuring the AKV. ++ The terraform access_policy definitions can be tricky to get working, especially if you are using cli auth. I found that most online examples use `data "azurerm_client_config" "current" {}` to grab the tenant id and current user id; however, this failed for me. I was able to get it working using `data "azuread_client_config" "current" {}`. See the file `kv.tf` for a working solution. + diff --git a/012-InfraAsCode-Terraform/Coach/Solution-05.md b/012-InfraAsCode-Terraform/Coach/Solution-05.md new file mode 100644 index 0000000000..e3760c6cb9 --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solution-05.md @@ -0,0 +1,7 @@ +# Challenge 5: Deploy a Virtual Machine - Coach's Guide + +[< Previous Challenge](./Solution-04.md) - **[Home](./README.md)** - [Next Challenge >](./Solution-06.md) + +## Notes & Guidance + +Be aware that while the sample at https://learn.microsoft.com/en-us/azure/virtual-machines/linux/quick-create-terraform is very useful/helpful, it is not 100% aligned with our challenges. Eg, Be sure that the participants do not blindly cut/paste the samples without understanding what they do. diff --git a/012-InfraAsCode-Terraform/Coach/Solution-06.md b/012-InfraAsCode-Terraform/Coach/Solution-06.md new file mode 100644 index 0000000000..a0ea3dced7 --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solution-06.md @@ -0,0 +1,11 @@ +# Challenge 6: Modules - Coach's Guide + +[< Previous Challenge](./Solution-05.md) - **[Home](./README.md)** - [Next Challenge >](./Solution-07.md) + +## Notes & Guidance + +In this challenge, the student is learning about modules. A VM and VNET are separated into modules to show how to break up monoliths and promote reuse. + +A dependent module should not assume anything about how a prior module operated. It's not a good practice to pass in the name of a resource-to-be-created to a module and then recreate a resource ID in the next module using that same name. Instead, the module that created the resource should output its resource ID, name, and other properties that might be required. The dependent module should use those output values as input parameters. + +Please review the solution in the Solutions folder. diff --git a/012-InfraAsCode-Terraform/Coach/Solution-07.md b/012-InfraAsCode-Terraform/Coach/Solution-07.md new file mode 100644 index 0000000000..ac9699c21f --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solution-07.md @@ -0,0 +1,7 @@ +# Challenge 7: Azure Container Apps (ACA) - Getting started - Coach's Guide + +[< Previous Challenge](./Solution-06.md) - **[Home](./README.md)** - [Next Challenge>](./Solution-08.md) + +## Notes & Guidance + +Please review the solution in the Solutions folder \ No newline at end of file diff --git a/012-InfraAsCode-Terraform/Coach/Solution-08.md b/012-InfraAsCode-Terraform/Coach/Solution-08.md new file mode 100644 index 0000000000..7e9f081e49 --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solution-08.md @@ -0,0 +1,8 @@ +# Challenge 8: Advanced Azure Container Apps (ACA) - Coach's Guide + +[< Previous Challenge](./Solution-07.md) - **[Home](./README.md)** + +## Notes & Guidance + +Please review the solution in the Solutions folder + diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Challenge 1/Challenge 1 - resource group.tf b/012-InfraAsCode-Terraform/Coach/Solutions/Challenge 1/Challenge 1 - resource group.tf deleted file mode 100644 index e92c62f337..0000000000 --- a/012-InfraAsCode-Terraform/Coach/Solutions/Challenge 1/Challenge 1 - resource group.tf +++ /dev/null @@ -1,11 +0,0 @@ -# Configure the Microsoft Azure Provider -provider "azurerm" { - subscription_id = "" - client_id = "" - client_secret = "" - tenant_id = "" -} -resource "azurerm_resource_group" "rg" { - name = "WTHTFRG" - location = "centralus" -} diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Challenge 2/Challenge 2 - vnet.tf b/012-InfraAsCode-Terraform/Coach/Solutions/Challenge 2/Challenge 2 - vnet.tf deleted file mode 100644 index 7e426ad805..0000000000 --- a/012-InfraAsCode-Terraform/Coach/Solutions/Challenge 2/Challenge 2 - vnet.tf +++ /dev/null @@ -1,28 +0,0 @@ -# Configure the Microsoft Azure Provider -provider "azurerm" { - subscription_id = "" - client_id = "" - client_secret = "" - tenant_id = "" -} -resource "azurerm_resource_group" "rg" { - name = "WTHTFRG" - location = "eastus" -} -resource "azurerm_virtual_network" "myterraformnetwork" { - name = "WTHVNetTF" - address_space = ["10.1.0.0/16"] - location = "eastus" - resource_group_name = "${azurerm_resource_group.rg.name}" - - tags = { - environment = "WTH Terraform" - } -} - -resource "azurerm_subnet" "myterraformsubnet" { - name = "default" - resource_group_name = "${azurerm_resource_group.rg.name}" - virtual_network_name = "${azurerm_virtual_network.myterraformnetwork.name}" - address_prefix = "10.1.0.0/24" -} diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Challenge 3/Challenge 3 - vnet with nsg.tf b/012-InfraAsCode-Terraform/Coach/Solutions/Challenge 3/Challenge 3 - vnet with nsg.tf deleted file mode 100644 index ee83f1a261..0000000000 --- a/012-InfraAsCode-Terraform/Coach/Solutions/Challenge 3/Challenge 3 - vnet with nsg.tf +++ /dev/null @@ -1,50 +0,0 @@ -# Configure the Microsoft Azure Provider -provider "azurerm" { - subscription_id = "" - client_id = "" - client_secret = "" - tenant_id = "" -} -resource "azurerm_resource_group" "rg" { - name = "WTHTFRG" - location = "eastus" -} -resource "azurerm_virtual_network" "myterraformnetwork" { - name = "WTHVNetTF" - address_space = ["10.1.0.0/16"] - location = "eastus" - resource_group_name = "${azurerm_resource_group.rg.name}" - - tags = { - environment = "WTH Terraform" - } -} - -resource "azurerm_subnet" "myterraformsubnet" { - name = "default" - resource_group_name = "${azurerm_resource_group.rg.name}" - virtual_network_name = "${azurerm_virtual_network.myterraformnetwork.name}" - address_prefix = "10.1.0.0/24" -} - -resource "azurerm_network_security_group" "myterraformnsg" { - name = "WTHNSG" - location = "eastus" - resource_group_name = "${azurerm_resource_group.rg.name}" - - security_rule { - name = "SSH" - priority = 1001 - direction = "Inbound" - access = "Allow" - protocol = "Tcp" - source_port_range = "*" - destination_port_range = "22" - source_address_prefix = "*" - destination_address_prefix = "*" - } - - tags = { - environment = "WTH Terraform" - } -} diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Challenge 4/Challenge 4 - variables.tf b/012-InfraAsCode-Terraform/Coach/Solutions/Challenge 4/Challenge 4 - variables.tf deleted file mode 100644 index f7afb57441..0000000000 --- a/012-InfraAsCode-Terraform/Coach/Solutions/Challenge 4/Challenge 4 - variables.tf +++ /dev/null @@ -1,36 +0,0 @@ -variable "azurerm" { - description = "The subscription_id, client_id, client_secret and tenant_id to setup Terraform access" - type = "map" -} -variable "location" { - description = "The location where resources are created" - default = "East US" -} - -variable "resource_group_name" { - description = "The name of the resource group in which the resources are created" -} - -variable "virtual_network_name" { - description = "The name for the virtual network" -} -variable "virtual_network_address_space" { - description = "The name for the virtual network" - type = "list" -} -variable "subnet" { - description = "The name and address prefix for the subnet" - type = "map" -} - -variable "nsg" { - description = "The name of the Network security group" -} -variable "nsg_security_rule_ssh" { - description = "The name, priority, direction, access, protocol, source_port_range, destination_port_range, source_address_prefix, destination_address_prefix for the SSH NSG security rule" - type = "map" -} -variable "tags" { - description = "The tags for the Azure resource" - type = "map" -} \ No newline at end of file diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Challenge 4/Challenge 4 - variables.tfvars b/012-InfraAsCode-Terraform/Coach/Solutions/Challenge 4/Challenge 4 - variables.tfvars deleted file mode 100644 index 94205a4be3..0000000000 --- a/012-InfraAsCode-Terraform/Coach/Solutions/Challenge 4/Challenge 4 - variables.tfvars +++ /dev/null @@ -1,35 +0,0 @@ -azurerm = { - subscription_id = "" - client_id = "" - client_secret = "" - tenant_id = "" -} - -location = "East US" -resource_group_name = "WTHTFRG" - -virtual_network_name = "WTHVNetTF" -virtual_network_address_space = ["10.1.0.0/16"] - -subnet = { - name = "default" - address_prefix = "10.1.0.0/24" -} - -nsg = "WTHNSG" - -nsg_security_rule_ssh = { - name = "SSH" - priority = 1001 - direction = "Inbound" - access = "Allow" - protocol = "Tcp" - source_port_range = "*" - destination_port_range = "22" - source_address_prefix = "*" - destination_address_prefix = "*" -} - -tags = { - environment = "WTH Terraform" -} diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Challenge 4/Challenge 4 - vnet with nsg and variables.tf b/012-InfraAsCode-Terraform/Coach/Solutions/Challenge 4/Challenge 4 - vnet with nsg and variables.tf deleted file mode 100644 index 2999a42725..0000000000 --- a/012-InfraAsCode-Terraform/Coach/Solutions/Challenge 4/Challenge 4 - vnet with nsg and variables.tf +++ /dev/null @@ -1,50 +0,0 @@ -# Configure the Microsoft Azure Provider -provider "azurerm" { - subscription_id = "${var.azurerm["subscription_id"]}" - client_id = "${var.azurerm["client_id"]}" - client_secret = "${var.azurerm["client_secret"]}" - tenant_id = "${var.azurerm["tenant_id"]}" -} -resource "azurerm_resource_group" "rg" { - name = "${var.resource_group_name}" - location = "${var.location}" -} -resource "azurerm_virtual_network" "myterraformnetwork" { - name = "${var.virtual_network_name}" - address_space = "${var.virtual_network_address_space}" - location = "${var.location}" - resource_group_name = "${azurerm_resource_group.rg.name}" - - tags = { - environment = "${var.tags["environment"]}" - } -} - -resource "azurerm_subnet" "myterraformsubnet" { - name = "${var.subnet["name"]}" - resource_group_name = "${azurerm_resource_group.rg.name}" - virtual_network_name = "${azurerm_virtual_network.myterraformnetwork.name}" - address_prefix = "${var.subnet["address_prefix"]}" -} - -resource "azurerm_network_security_group" "myterraformnsg" { - name = "${var.nsg}" - location = "${var.location}" - resource_group_name = "${azurerm_resource_group.rg.name}" - - security_rule { - name = "${var.nsg_security_rule_ssh["name"]}" - priority = "${var.nsg_security_rule_ssh["priority"]}" - direction = "${var.nsg_security_rule_ssh["direction"]}" - access = "${var.nsg_security_rule_ssh["access"]}" - protocol = "${var.nsg_security_rule_ssh["protocol"]}" - source_port_range = "${var.nsg_security_rule_ssh["source_port_range"]}" - destination_port_range = "${var.nsg_security_rule_ssh["destination_port_range"]}" - source_address_prefix = "${var.nsg_security_rule_ssh["source_address_prefix"]}" - destination_address_prefix = "${var.nsg_security_rule_ssh["destination_address_prefix"]}" - } - - tags = { - environment = "${var.tags["environment"]}" - } -} \ No newline at end of file diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Challenge 5/Challenge 5 - create Ubuntu VM.tf b/012-InfraAsCode-Terraform/Coach/Solutions/Challenge 5/Challenge 5 - create Ubuntu VM.tf deleted file mode 100644 index d3e586431e..0000000000 --- a/012-InfraAsCode-Terraform/Coach/Solutions/Challenge 5/Challenge 5 - create Ubuntu VM.tf +++ /dev/null @@ -1,141 +0,0 @@ -# Configure the Microsoft Azure Provider -provider "azurerm" { - subscription_id = "" - client_id = "" - client_secret = "" - tenant_id = "" -} -resource "azurerm_resource_group" "rg" { - name = "${var.resource_group_name}" - location = "${var.location}" -} -resource "azurerm_virtual_network" "myterraformnetwork" { - name = "${var.virtual_network_name}" - address_space = "${var.virtual_network_address_space}" - location = "${var.location}" - resource_group_name = "${azurerm_resource_group.rg.name}" - - tags = { - environment = "${var.tags["environment"]}" - } -} - -resource "azurerm_subnet" "myterraformsubnet" { - name = "${var.subnet["name"]}" - resource_group_name = "${azurerm_resource_group.rg.name}" - virtual_network_name = "${azurerm_virtual_network.myterraformnetwork.name}" - address_prefix = "${var.subnet["address_prefix"]}" -} - -resource "azurerm_network_security_group" "myterraformnsg" { - name = "${var.nsg}" - location = "${var.location}" - resource_group_name = "${azurerm_resource_group.rg.name}" - - security_rule { - name = "${var.nsg_security_rule_ssh["name"]}" - priority = "${var.nsg_security_rule_ssh["priority"]}" - direction = "${var.nsg_security_rule_ssh["direction"]}" - access = "${var.nsg_security_rule_ssh["access"]}" - protocol = "${var.nsg_security_rule_ssh["protocol"]}" - source_port_range = "${var.nsg_security_rule_ssh["source_port_range"]}" - destination_port_range = "${var.nsg_security_rule_ssh["destination_port_range"]}" - source_address_prefix = "${var.nsg_security_rule_ssh["source_address_prefix"]}" - destination_address_prefix = "${var.nsg_security_rule_ssh["destination_address_prefix"]}" - } - - tags { - environment = "${var.tags["environment"]}" - } -} -resource "azurerm_public_ip" "myterraformpublicip" { - name = "${var.azurerm_public_ip["name"]}" - location = "${var.location}" - resource_group_name = "${azurerm_resource_group.rg.name}" - allocation_method = "${var.azurerm_public_ip["allocation_method"]}" - - tags { - environment = "${var.tags["environment"]}" - } -}resource "azurerm_network_interface" "myterraformnic" { - name = "${var.azurerm_network_interface}" - location = "${var.location}" - resource_group_name = "${azurerm_resource_group.rg.name}" - network_security_group_id = "${azurerm_network_security_group.myterraformnsg.id}" - - ip_configuration { - name = "${var.azurerm_network_interface_ip_configuration["name"]}" - subnet_id = "${azurerm_subnet.myterraformsubnet.id}" - private_ip_address_allocation = "${var.azurerm_network_interface_ip_configuration["private_ip_address_allocation"]}" - public_ip_address_id = "${azurerm_public_ip.myterraformpublicip.id}" - } - - tags = { - environment = "${var.tags["environment"]}" - } -} - -resource "random_id" "randomId" { - keepers = { - # Generate a new ID only when a new resource group is defined - resource_group = "${azurerm_resource_group.rg.name}" - } - - byte_length = 8 -} - -resource "azurerm_storage_account" "mystorageaccount" { - name = "diag${random_id.randomId.hex}" - resource_group_name = "${azurerm_resource_group.rg.name}" - location = "${var.location}" - account_replication_type = "${var.azurerm_storage_account["account_replication_type"]}" - account_tier = "${var.azurerm_storage_account["account_tier"]}" - - tags = { - environment = "${var.tags["environment"]}" - } -} - -resource "azurerm_virtual_machine" "myterraformvm" { - name = "${var.azurerm_virtual_machine["name"]}" - location = "${var.location}" - resource_group_name = "${azurerm_resource_group.rg.name}" - network_interface_ids = ["${azurerm_network_interface.myterraformnic.id}"] - vm_size = "${var.azurerm_virtual_machine["vm_size"]}" - - storage_os_disk { - name = "${var.azurerm_virtual_machine_storage_os_disk["name"]}" - caching = "${var.azurerm_virtual_machine_storage_os_disk["caching"]}" - create_option = "${var.azurerm_virtual_machine_storage_os_disk["create_option"]}" - managed_disk_type = "${var.azurerm_virtual_machine_storage_os_disk["managed_disk_type"]}" - } - - storage_image_reference { - publisher = "${var.azurerm_virtual_machine_storage_image_reference["publisher"]}" - offer = "${var.azurerm_virtual_machine_storage_image_reference["offer"]}" - sku = "${var.azurerm_virtual_machine_storage_image_reference["sku"]}" - version = "${var.azurerm_virtual_machine_storage_image_reference["version"]}" - } - - os_profile { - computer_name = "${var.os_profile["computer_name"]}" - admin_username = "${var.os_profile["admin_username"]}" - } - - os_profile_linux_config { - disable_password_authentication = "${var.os_profile_linux_config_disable_password_authentication}" - ssh_keys { - path = "${var.os_profile_linux_config_ssh_keys["path"]}" - key_data = "${var.os_profile_linux_config_ssh_keys["key_data"]}" - } - } - - boot_diagnostics { - enabled = "true" - storage_uri = "${azurerm_storage_account.mystorageaccount.primary_blob_endpoint}" - } - - tags = { - environment = "WTH Terraform Demo" - } -} \ No newline at end of file diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Challenge 5/Challenge 5 - variables.tf b/012-InfraAsCode-Terraform/Coach/Solutions/Challenge 5/Challenge 5 - variables.tf deleted file mode 100644 index 1d15d825a7..0000000000 --- a/012-InfraAsCode-Terraform/Coach/Solutions/Challenge 5/Challenge 5 - variables.tf +++ /dev/null @@ -1,78 +0,0 @@ -variable "azurerm" { - description = "The subscription_id, client_id, client_secret and tenant_id to setup Terraform access" - type = "map" -} -variable "location" { - description = "The location where resources are created" - default = "East US" -} - -variable "resource_group_name" { - description = "The name of the resource group in which the resources are created" -} - -variable "virtual_network_name" { - description = "The name for the virtual network" -} -variable "virtual_network_address_space" { - description = "The name for the virtual network" - type = "list" -} -variable "subnet" { - description = "The name and address prefix for the subnet" - type = "map" -} - -variable "nsg" { - description = "The name of the Network security group" -} -variable "nsg_security_rule_ssh" { - description = "The name, priority, direction, access, protocol, source_port_range, destination_port_range, source_address_prefix, destination_address_prefix for the SSH NSG security rule" - type = "map" -} -variable "tags" { - description = "The tags for the Azure resource" - type = "map" -} -variable "azurerm_network_interface" { - description = "Settings for the VM NIC" - type = "string" -} - -variable "azurerm_network_interface_ip_configuration" { - description = "Setings for the VM's IP configuration" - type = "map" -} -variable "azurerm_public_ip" { - description = "Settings for the VM's IP settings (e.g. name, allocation)" - type = "map" -} -variable "azurerm_virtual_machine" { - description = "Virtual machine settings" - type = "map" -} -variable "os_profile_linux_config_disable_password_authentication" { - description = "Password authentication setting for linux" -} -variable "os_profile" { - description = "OS Profile settings" - type = "map" -} - -variable "azurerm_storage_account" { - description = "Storage account settings" - type = "map" -} - -variable "os_profile_linux_config_ssh_keys" { - description = "SSH settings for linux" - type = "map" -} -variable "azurerm_virtual_machine_storage_os_disk" { - description = "Storage settings for the VM" - type = "map" -} -variable "azurerm_virtual_machine_storage_image_reference" { - description = "Storage image reference settings for the VM" - type = "map" -} \ No newline at end of file diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Challenge 5/Challenge 5 - variables.tfvars b/012-InfraAsCode-Terraform/Coach/Solutions/Challenge 5/Challenge 5 - variables.tfvars deleted file mode 100644 index 9904dd7e49..0000000000 --- a/012-InfraAsCode-Terraform/Coach/Solutions/Challenge 5/Challenge 5 - variables.tfvars +++ /dev/null @@ -1,82 +0,0 @@ -azurerm = { - subscription_id = "" - client_id = "" - client_secret = "" - tenant_id = "" -} - -location = "East US" -resource_group_name = "WTHTFRG" - -virtual_network_name = "WTHVNetTF" -virtual_network_address_space = ["10.1.0.0/16"] - -subnet = { - name = "default" - address_prefix = "10.1.0.0/24" -} - -nsg = "WTHNSG" - -nsg_security_rule_ssh = { - name = "SSH" - priority = 1001 - direction = "Inbound" - access = "Allow" - protocol = "Tcp" - source_port_range = "*" - destination_port_range = "22" - source_address_prefix = "*" - destination_address_prefix = "*" -} - -tags = { - environment = "WTH Terraform" -} -azurerm_network_interface = "WTHUbuntuNIC" - -azurerm_public_ip = { - name = "myPublicIP" - allocation_method = "Dynamic" -} - azurerm_storage_account = { - account_replication_type = "LRS" - account_tier = "Standard" -} - -azurerm_network_interface_ip_configuration = { - name = "WTHUbuntuNICConfiguration" - private_ip_address_allocation = "Dynamic" -} - -os_profile = { - computer_name = "WTHUbuntuVM01" - admin_username = "azureuser" -} - -azurerm_virtual_machine = { - name = "WTHUbuntuVM01" - vm_size = "Standard_DS1_v2" -} - -azurerm_virtual_machine_storage_os_disk = { - name = "myOsDisk" - caching = "ReadWrite" - create_option = "FromImage" - managed_disk_type = "Premium_LRS" -} - -azurerm_virtual_machine_storage_image_reference = { - publisher = "Canonical" - offer = "UbuntuServer" - sku = "18.04-LTS" - version = "latest" -} - -os_profile_linux_config_disable_password_authentication = true - -os_profile_linux_config_ssh_keys = { - path = "/home/azureuser/.ssh/authorized_keys" - key_data = "ssh-rsa AAAAB3NzaC1yc2EAAAfV+RoIhxrmUabNA9pVWGloxi6CE3PgJGqzijClAvFU8VT9Gu0xzY8LoAS0R0oF7/Zhac6cWzxICcPVMlKBaWL3etpGRvrK8xO3nK2qHmB1EwuKw+57owriTslNyblXt2WT/c2kRGKo5HFLufh/P+rDyB/hvd1Xy75IEW/BGTfhT0YbYLntYHF7K5heQjrMW4kW6eWx pete@cc-9b61a39f-66fcd9ccfb-sb8br" -} - diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Challenge 6/.terraform/plugins/windows_amd64/lock.json b/012-InfraAsCode-Terraform/Coach/Solutions/Challenge 6/.terraform/plugins/windows_amd64/lock.json deleted file mode 100644 index 229d9d849c..0000000000 --- a/012-InfraAsCode-Terraform/Coach/Solutions/Challenge 6/.terraform/plugins/windows_amd64/lock.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "azurerm": "c8af23cb462cfc8815eeca6c609b333a70df8b4ef85bae07a40d11683f914df1", - "random": "932cf41ab332d0c31f8c50141cb236007b83f722269103deae82459a7a6e0aeb" -} \ No newline at end of file diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Challenge 6/Challenge 6 - Create Ubuntu VM with Packer.json b/012-InfraAsCode-Terraform/Coach/Solutions/Challenge 6/Challenge 6 - Create Ubuntu VM with Packer.json deleted file mode 100644 index 3082ef5637..0000000000 --- a/012-InfraAsCode-Terraform/Coach/Solutions/Challenge 6/Challenge 6 - Create Ubuntu VM with Packer.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "builders": [{ - "type": "azure-arm", - "subscription_id" : "f86c3XXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX", - "client_id" : "b12cXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX", - "client_secret" : "d1b7XXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX", - "tenant_id" : "72f9XXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX", - "managed_image_resource_group_name": "WTHTFRG", - "managed_image_name": "packerImage", - - "os_type": "Linux", - "image_publisher": "Canonical", - "image_offer": "UbuntuServer", - "image_sku": "18.04-LTS", - - "azure_tags": { - "task": "Image deployment" - }, - - "location": "East US", - "vm_size": "Standard_DS2_v2" - }], - "provisioners": [{ - "execute_command": "chmod +x {{ .Path }}; {{ .Vars }} sudo -E sh '{{ .Path }}'", - "inline": [ - "apt-get update", - "apt-get upgrade -y", - "apt-get -y install nginx", - - "/usr/sbin/waagent -force -deprovision+user && export HISTSIZE=0 && sync" - ], - "inline_shebang": "/bin/sh -x", - "type": "shell" - }] - } \ No newline at end of file diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Challenge 6/Challenge 6 - Create Ubuntu VM. with Packer.tf b/012-InfraAsCode-Terraform/Coach/Solutions/Challenge 6/Challenge 6 - Create Ubuntu VM. with Packer.tf deleted file mode 100644 index 7acfb20b42..0000000000 --- a/012-InfraAsCode-Terraform/Coach/Solutions/Challenge 6/Challenge 6 - Create Ubuntu VM. with Packer.tf +++ /dev/null @@ -1,160 +0,0 @@ -# Configure the Microsoft Azure Provider -provider "azurerm" { - subscription_id = "" - client_id = "" - client_secret = "" - tenant_id = "" -} -resource "azurerm_resource_group" "rg" { - name = "${var.resource_group_name}" - location = "${var.location}" -} -resource "azurerm_virtual_network" "myterraformnetwork" { - name = "${var.virtual_network_name}" - address_space = "${var.virtual_network_address_space}" - location = "${var.location}" - resource_group_name = "${azurerm_resource_group.rg.name}" - - tags = { - environment = "${var.tags["environment"]}" - } -} - -resource "azurerm_subnet" "myterraformsubnet" { - name = "${var.subnet["name"]}" - resource_group_name = "${azurerm_resource_group.rg.name}" - virtual_network_name = "${azurerm_virtual_network.myterraformnetwork.name}" - address_prefix = "${var.subnet["address_prefix"]}" -} - -resource "azurerm_network_security_group" "myterraformnsg" { - name = "${var.nsg}" - location = "${var.location}" - resource_group_name = "${azurerm_resource_group.rg.name}" - - security_rule { - name = "${var.nsg_security_rule_ssh["name"]}" - priority = "${var.nsg_security_rule_ssh["priority"]}" - direction = "${var.nsg_security_rule_ssh["direction"]}" - access = "${var.nsg_security_rule_ssh["access"]}" - protocol = "${var.nsg_security_rule_ssh["protocol"]}" - source_port_range = "${var.nsg_security_rule_ssh["source_port_range"]}" - destination_port_range = "${var.nsg_security_rule_ssh["destination_port_range"]}" - source_address_prefix = "${var.nsg_security_rule_ssh["source_address_prefix"]}" - destination_address_prefix = "${var.nsg_security_rule_ssh["destination_address_prefix"]}" - } - - security_rule { - name = "${var.nsg_security_rule_http["name"]}" - priority = "${var.nsg_security_rule_http["priority"]}" - direction = "${var.nsg_security_rule_http["direction"]}" - access = "${var.nsg_security_rule_http["access"]}" - protocol = "${var.nsg_security_rule_http["protocol"]}" - source_port_range = "${var.nsg_security_rule_http["source_port_range"]}" - destination_port_range = "${var.nsg_security_rule_http["destination_port_range"]}" - source_address_prefix = "${var.nsg_security_rule_http["source_address_prefix"]}" - destination_address_prefix = "${var.nsg_security_rule_http["destination_address_prefix"]}" - } - - tags = { - environment = "${var.tags["environment"]}" - } -} -resource "azurerm_public_ip" "myterraformpublicip" { - name = "${var.azurerm_public_ip["name"]}" - location = "${var.location}" - resource_group_name = "${azurerm_resource_group.rg.name}" - allocation_method = "${var.azurerm_public_ip["allocation_method"]}" - - tags = { - environment = "${var.tags["environment"]}" - } -}resource "azurerm_network_interface" "myterraformnic" { - name = "${var.azurerm_network_interface}" - location = "${var.location}" - resource_group_name = "${azurerm_resource_group.rg.name}" - network_security_group_id = "${azurerm_network_security_group.myterraformnsg.id}" - - ip_configuration { - name = "${var.azurerm_network_interface_ip_configuration["name"]}" - subnet_id = "${azurerm_subnet.myterraformsubnet.id}" - private_ip_address_allocation = "${var.azurerm_network_interface_ip_configuration["private_ip_address_allocation"]}" - public_ip_address_id = "${azurerm_public_ip.myterraformpublicip.id}" - } - - tags = { - environment = "${var.tags["environment"]}" - } -} - -resource "random_id" "randomId" { - keepers = { - # Generate a new ID only when a new resource group is defined - resource_group = "${azurerm_resource_group.rg.name}" - } - - byte_length = 8 -} - -resource "azurerm_storage_account" "mystorageaccount" { - name = "diag${random_id.randomId.hex}" - resource_group_name = "${azurerm_resource_group.rg.name}" - location = "${var.location}" - account_replication_type = "${var.azurerm_storage_account["account_replication_type"]}" - account_tier = "${var.azurerm_storage_account["account_tier"]}" - - tags = { - environment = "${var.tags["environment"]}" - } -} -//Linux Image created by packer -data "azurerm_resource_group" "image" { - name = "${azurerm_resource_group.rg.name}" -} - -data "azurerm_image" "image" { - name = "packerImage" - resource_group_name = "${data.azurerm_resource_group.image.name}" -} -resource "azurerm_virtual_machine" "myterraformvm" { - name = "${var.azurerm_virtual_machine["name"]}" - location = "${var.location}" - resource_group_name = "${azurerm_resource_group.rg.name}" - network_interface_ids = ["${azurerm_network_interface.myterraformnic.id}"] - vm_size = "${var.azurerm_virtual_machine["vm_size"]}" - - storage_os_disk { - name = "${var.azurerm_virtual_machine_storage_os_disk["name"]}" - caching = "${var.azurerm_virtual_machine_storage_os_disk["caching"]}" - create_option = "${var.azurerm_virtual_machine_storage_os_disk["create_option"]}" - managed_disk_type = "${var.azurerm_virtual_machine_storage_os_disk["managed_disk_type"]}" - } - - #Packer created image reference - storage_image_reference { - id = "${data.azurerm_image.image.id}" - } - - - os_profile { - computer_name = "${var.os_profile["computer_name"]}" - admin_username = "${var.os_profile["admin_username"]}" - } - - os_profile_linux_config { - disable_password_authentication = "${var.os_profile_linux_config_disable_password_authentication}" - ssh_keys { - path = "${var.os_profile_linux_config_ssh_keys["path"]}" - key_data = "${var.os_profile_linux_config_ssh_keys["key_data"]}" - } - } - - boot_diagnostics { - enabled = "true" - storage_uri = "${azurerm_storage_account.mystorageaccount.primary_blob_endpoint}" - } - - tags = { - environment = "WTH Terraform Demo" - } -} \ No newline at end of file diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Challenge 6/Challenge 6 - variables.tf b/012-InfraAsCode-Terraform/Coach/Solutions/Challenge 6/Challenge 6 - variables.tf deleted file mode 100644 index ef5acfb936..0000000000 --- a/012-InfraAsCode-Terraform/Coach/Solutions/Challenge 6/Challenge 6 - variables.tf +++ /dev/null @@ -1,78 +0,0 @@ -variable "azurerm" { - description = "The subscription_id, client_id, client_secret and tenant_id to setup Terraform access" - type = "map" -} -variable "location" { - description = "The location where resources are created" - default = "East US" -} - -variable "resource_group_name" { - description = "The name of the resource group in which the resources are created" -} - -variable "virtual_network_name" { - description = "The name for the virtual network" -} -variable "virtual_network_address_space" { - description = "The name for the virtual network" - type = "list" -} -variable "subnet" { - description = "The name and address prefix for the subnet" - type = "map" -} - -variable "nsg" { - description = "The name of the Network security group" -} -variable "nsg_security_rule_ssh" { - description = "The name, priority, direction, access, protocol, source_port_range, destination_port_range, source_address_prefix, destination_address_prefix for the SSH NSG security rule" - type = "map" -} -variable "nsg_security_rule_http" { - description = "The name, priority, direction, access, protocol, source_port_range, destination_port_range, source_address_prefix, destination_address_prefix for the HTTP NSG security rule" - type = "map" -} -variable "tags" { - description = "The tags for the Azure resource" - type = "map" -} -variable "azurerm_network_interface" { - description = "Settings for the VM NIC" - type = "string" -} - -variable "azurerm_network_interface_ip_configuration" { - description = "Setings for the VM's IP configuration" - type = "map" -} -variable "azurerm_public_ip" { - description = "Settings for the VM's IP settings (e.g. name, allocation)" - type = "map" -} -variable "azurerm_virtual_machine" { - description = "Virtual machine settings" - type = "map" -} -variable "os_profile_linux_config_disable_password_authentication" { - description = "Password authentication setting for linux" -} -variable "os_profile" { - description = "OS Profile settings" - type = "map" -} - -variable "azurerm_storage_account" { - description = "Storage account settings" - type = "map" -} - -variable "os_profile_linux_config_ssh_keys" { - description = "SSH settings for linux" - type = "map" -} -variable "azurerm_virtual_machine_storage_os_disk" { - description = "Storage settings for the VM" - type = "map" -} diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Challenge 6/Challenge 6 - variables.tfvars b/012-InfraAsCode-Terraform/Coach/Solutions/Challenge 6/Challenge 6 - variables.tfvars deleted file mode 100644 index bb7bbac053..0000000000 --- a/012-InfraAsCode-Terraform/Coach/Solutions/Challenge 6/Challenge 6 - variables.tfvars +++ /dev/null @@ -1,87 +0,0 @@ -azurerm = { - subscription_id = "" - client_id = "" - client_secret = "" - tenant_id = "" -} - -location = "East US" -resource_group_name = "WTHTFRG" - -virtual_network_name = "WTHVNetTF" -virtual_network_address_space = ["10.1.0.0/16"] - -subnet = { - name = "default" - address_prefix = "10.1.0.0/24" -} - -nsg = "WTHNSG" - -nsg_security_rule_ssh = { - name = "SSH" - priority = 1001 - direction = "Inbound" - access = "Allow" - protocol = "Tcp" - source_port_range = "*" - destination_port_range = "22" - source_address_prefix = "*" - destination_address_prefix = "*" -} - -nsg_security_rule_http = { - name = "HTTP" - priority = 1002 - direction = "Inbound" - access = "Allow" - protocol = "Tcp" - source_port_range = "*" - destination_port_range = "80" - source_address_prefix = "*" - destination_address_prefix = "*" -} - -tags = { - environment = "WTH Terraform" -} -azurerm_network_interface = "WTHUbuntuNIC" - -azurerm_public_ip = { - name = "myPublicIP" - allocation_method = "Dynamic" -} -azurerm_storage_account = { - account_replication_type = "LRS" - account_tier = "Standard" -} - -azurerm_network_interface_ip_configuration = { - name = "WTHUbuntuNICConfiguration" - private_ip_address_allocation = "Dynamic" -} - -os_profile = { - computer_name = "WTHUbuntuVM01" - admin_username = "azureuser" -} - -azurerm_virtual_machine = { - name = "WTHUbuntuVM01" - vm_size = "Standard_DS1_v2" -} - -azurerm_virtual_machine_storage_os_disk = { - name = "myOsDisk" - caching = "ReadWrite" - create_option = "FromImage" - managed_disk_type = "Premium_LRS" -} - -os_profile_linux_config_disable_password_authentication = true - -os_profile_linux_config_ssh_keys = { - path = "/home/azureuser/.ssh/authorized_keys" - key_data = "ssh-rsa AAAAB3NzacjVxasxEbZ2otJpJpK6DACuktMDeBtj3QlctK0uiWqaErxwDAYXmqDtp6Gkihg6kJtZxC1y7t2N/dc5/zAt16MfV+RoIhxrmUabNA9pVWGloxi6CE3PgJGqzijClAvFU8VT9Gu0xzY8LoAS0R0oF7/Zhac6cWzxICcPVMlKBaWL3etpGRvrK8xO3nK2qHmB1EwuKw+57owriTslNyblXt2WT/c2kRGKo5HFLufh/P+rDyB/hvd1Xy75IEW/BGTfhT0YbYLntYHF7K5heQjrMW4kW6eWx pete@cc-9b61a39f-66fcd9ccfb-sb8br" -} - diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-01/challenge-01.sh b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-01/challenge-01.sh new file mode 100644 index 0000000000..4c8c64bb70 --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-01/challenge-01.sh @@ -0,0 +1,34 @@ +# If self-deploying the challenges, recommend adding a prefix or suffix to Azure resources. +# For example, resourceGroupName = "-challenge-01-rg" + +##### PART 1 ############### + +SUFFIX='lnc01' +LOCATION='westus3' +RG="tfstate-${SUFFIX}" +SANAME="tfstate${SUFFIX}" +CONTAINER='tfstate' + +# Create RG +az group create --name $RG --location $LOCATION +# Create storage account +az storage account create --resource-group $RG --name $SANAME --sku Standard_LRS --encryption-services blob +# Create blob container +az storage container create --name $CONTAINER --account-name $SANAME + +echo "You will need to configure the backend of your challenge-01.tf as follows:" +echo " +backend \"azurerm\" { + resource_group_name = \"$RG\" + storage_account_name = \"$SANAME\" + container_name = \"$CONTAINER\" + key = "terraform.tfstate" +}" + +# Part 2 +terraform init +terraform validate +terraform plan +terraform output storageid + + diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-01/main01.tf b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-01/main01.tf new file mode 100644 index 0000000000..ab5425cbd4 --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-01/main01.tf @@ -0,0 +1,50 @@ +# Assumption is you will be using az cli authentication +terraform { + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = ">=3.0.0" + } + } + backend "azurerm" { + resource_group_name = "tfstate-lnc01" + storage_account_name = "tfstatelnc01" + container_name = "tfstate" + key = "terraform.tfstate" + } +} + +# Configure the Microsoft Azure Provider +provider "azurerm" { + features {} +} + +# Variables +variable "rgname" { + type = string +} +variable "location" { + type = string +} +variable "saname" { + type = string +} + +# Resources +resource "azurerm_resource_group" "tfchallenge" { + name = var.rgname + location = var.location +} + +resource "azurerm_storage_account" "this" { + name = var.saname + resource_group_name = var.rgname + location = var.location + account_tier = "Standard" + account_replication_type = "LRS" +} + +# Outputs +output "storageid" { + value = azurerm_storage_account.this.id +} \ No newline at end of file diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-01/terraform.tfvars b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-01/terraform.tfvars new file mode 100644 index 0000000000..cba9f9eb29 --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-01/terraform.tfvars @@ -0,0 +1,3 @@ +rgname = "ch01rg" +location = "WestUS3" +saname = "ch01lnc01" # this must be a globally unique name; likely you will need to change this diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-02/challenge-02.sh b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-02/challenge-02.sh new file mode 100644 index 0000000000..911683c05d --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-02/challenge-02.sh @@ -0,0 +1,9 @@ +# If self-deploying the challenges, recommend adding a prefix or suffix to Azure resources. +# For example, resourceGroupName = "-challenge-01-rg" + +terraform init +terraform validate +terraform plan +terraform output + + diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-02/main02.tf b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-02/main02.tf new file mode 100644 index 0000000000..9529885bcd --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-02/main02.tf @@ -0,0 +1,26 @@ +# Resources +resource "random_string" "suffix" { + length = 4 + special = false + upper = false +} + +resource "azurerm_resource_group" "tfchallenge" { + name = var.rgname + location = var.location +} + +resource "azurerm_storage_account" "this" { + name = "${var.saname}${random_string.suffix.result}" + resource_group_name = azurerm_resource_group.tfchallenge.name + location = azurerm_resource_group.tfchallenge.location + account_tier = "Standard" + account_replication_type = var.geoRedundancy ? "GRS" : "LRS" +} + +resource "azurerm_storage_container" "thiscontainer" { + name = var.containername + storage_account_name = azurerm_storage_account.this.name + container_access_type = "blob" +} + diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-02/outputs.tf b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-02/outputs.tf new file mode 100644 index 0000000000..f713c1163f --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-02/outputs.tf @@ -0,0 +1,11 @@ +# Outputs +output "storageid" { + value = azurerm_storage_account.this.id +} +output "storagename" { + value = azurerm_storage_account.this.name +} + +output "bloburi" { + value = azurerm_storage_account.this.primary_blob_endpoint +} diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-02/terraform.tf b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-02/terraform.tf new file mode 100644 index 0000000000..618ffbcb7c --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-02/terraform.tf @@ -0,0 +1,23 @@ +# Assumption is you will be using az cli authentication +terraform { + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = ">=3.0.0" + } + random = { + source = "hashicorp/random" + } + } + backend "azurerm" { + resource_group_name = "tfstate-lnc01" + storage_account_name = "tfstatelnc01" + container_name = "tfstate" + key = "terraform.tfstate" + } +} + +# Configure the Microsoft Azure Provider +provider "azurerm" { + features {} +} \ No newline at end of file diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-02/terraform.tfvars b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-02/terraform.tfvars new file mode 100644 index 0000000000..202b282579 --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-02/terraform.tfvars @@ -0,0 +1,4 @@ +# Yes, this example still refereces CH01. If you change it, the resources will be re-created. +rgname = "ch01rg" +location = "WestUS3" +saname = "ch01lnc01" \ No newline at end of file diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-02/variables.tf b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-02/variables.tf new file mode 100644 index 0000000000..17adf7b65b --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-02/variables.tf @@ -0,0 +1,21 @@ +# Variables +variable "rgname" { + type = string +} +variable "location" { + type = string +} +variable "saname" { + type = string +} + +variable "geoRedundancy" { + type = bool + default = false +} + +variable "containername" { + type = string + default = "mycontainer" +} + diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-03/challenge-03.sh b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-03/challenge-03.sh new file mode 100644 index 0000000000..911683c05d --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-03/challenge-03.sh @@ -0,0 +1,9 @@ +# If self-deploying the challenges, recommend adding a prefix or suffix to Azure resources. +# For example, resourceGroupName = "-challenge-01-rg" + +terraform init +terraform validate +terraform plan +terraform output + + diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-03/main03.tf b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-03/main03.tf new file mode 100644 index 0000000000..0e9590cb24 --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-03/main03.tf @@ -0,0 +1,45 @@ +# Resources +resource "random_string" "suffix" { + length = 4 + special = false + upper = false +} + +resource "azurerm_resource_group" "tfchallenge" { + name = var.rgname + location = var.location +} + +resource "azurerm_storage_account" "this" { + name = "${var.saname}${random_string.suffix.result}" + resource_group_name = azurerm_resource_group.tfchallenge.name + location = azurerm_resource_group.tfchallenge.location + account_tier = "Standard" + account_replication_type = var.geoRedundancy ? "GRS" : "LRS" +} + +resource "azurerm_storage_container" "thiscontainer" { + name = var.containername + storage_account_name = azurerm_storage_account.this.name + container_access_type = "blob" +} + +resource "azurerm_storage_container" "container01" { + count = 3 + + name = "${var.containername}-${count.index}" + storage_account_name = azurerm_storage_account.this.name + container_access_type = "blob" +} + +variable "containersuffixlist" { + type = list + default = ["a", "b", "c"] +} + +resource "azurerm_storage_container" "container02" { + for_each = toset(var.containersuffixlist) + name = "${var.containername}-${each.key}" + storage_account_name = azurerm_storage_account.this.name + container_access_type = "blob" +} \ No newline at end of file diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-03/terraform.tf b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-03/terraform.tf new file mode 100644 index 0000000000..618ffbcb7c --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-03/terraform.tf @@ -0,0 +1,23 @@ +# Assumption is you will be using az cli authentication +terraform { + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = ">=3.0.0" + } + random = { + source = "hashicorp/random" + } + } + backend "azurerm" { + resource_group_name = "tfstate-lnc01" + storage_account_name = "tfstatelnc01" + container_name = "tfstate" + key = "terraform.tfstate" + } +} + +# Configure the Microsoft Azure Provider +provider "azurerm" { + features {} +} \ No newline at end of file diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-03/terraform.tfvars b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-03/terraform.tfvars new file mode 100644 index 0000000000..202b282579 --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-03/terraform.tfvars @@ -0,0 +1,4 @@ +# Yes, this example still refereces CH01. If you change it, the resources will be re-created. +rgname = "ch01rg" +location = "WestUS3" +saname = "ch01lnc01" \ No newline at end of file diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-03/variables.tf b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-03/variables.tf new file mode 100644 index 0000000000..17adf7b65b --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-03/variables.tf @@ -0,0 +1,21 @@ +# Variables +variable "rgname" { + type = string +} +variable "location" { + type = string +} +variable "saname" { + type = string +} + +variable "geoRedundancy" { + type = bool + default = false +} + +variable "containername" { + type = string + default = "mycontainer" +} + diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-04/challenge-04.sh b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-04/challenge-04.sh new file mode 100644 index 0000000000..a54d601af0 --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-04/challenge-04.sh @@ -0,0 +1,10 @@ +# If self-deploying the challenges, recommend adding a prefix or suffix to Azure resources. +# For example, resourceGroupName = "-challenge-01-rg" + +terraform init +terraform validate +terraform plan +terraform output +terraform state list + + diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-04/kv.tf b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-04/kv.tf new file mode 100644 index 0000000000..da9d5181ff --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-04/kv.tf @@ -0,0 +1,56 @@ +data "azurerm_client_config" "current" {} +data "azuread_client_config" "current" {} + +output "aadobject_id" { + value = data.azuread_client_config.current.object_id +} + +output "azrmobject_id" { + value = data.azurerm_client_config.current.object_id +} + +variable "kv_sku_name" { + type = string + description = "The SKU of the vault to be created." + default = "standard" +} + +variable "secret_permissions" { + type = list(string) + description = "List of secret permissions." + default = ["Set", "Get", "List"] +} + +resource "azurerm_key_vault" "vault" { + name = "${var.vaultnameprefix}${random_string.suffix.result}" + resource_group_name = azurerm_resource_group.tfchallenge.name + location = azurerm_resource_group.tfchallenge.location + tenant_id = data.azurerm_client_config.current.tenant_id + sku_name = var.kv_sku_name + soft_delete_retention_days = 7 + + timeouts { + create = "5m" + delete = "5m" + } + + access_policy { + tenant_id = data.azurerm_client_config.current.tenant_id + // object_id = data.external.user.result.id + object_id = data.azuread_client_config.current.object_id + + secret_permissions = var.secret_permissions + } +} + +resource "random_password" "password" { + length = 16 + special = true +} + +resource "azurerm_key_vault_secret" "thissecret" { + key_vault_id = azurerm_key_vault.vault.id + name = "mysecret" + value = random_password.password.result + +} \ No newline at end of file diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-04/main04.tf b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-04/main04.tf new file mode 100644 index 0000000000..74ff8b72b0 --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-04/main04.tf @@ -0,0 +1,46 @@ + +# Resources +resource "random_string" "suffix" { + length = 4 + special = false + upper = false +} + +resource "azurerm_resource_group" "tfchallenge" { + name = var.rgname + location = var.location +} + +resource "azurerm_storage_account" "this" { + name = "${var.saname}${random_string.suffix.result}" + resource_group_name = azurerm_resource_group.tfchallenge.name + location = azurerm_resource_group.tfchallenge.location + account_tier = "Standard" + account_replication_type = var.geoRedundancy ? "GRS" : "LRS" +} + +resource "azurerm_storage_container" "thiscontainer" { + name = var.containername + storage_account_name = azurerm_storage_account.this.name + container_access_type = "blob" +} + +resource "azurerm_storage_container" "container01" { + count = 3 + + name = "${var.containername}-${count.index}" + storage_account_name = azurerm_storage_account.this.name + container_access_type = "blob" +} + +variable "containersuffixlist" { + type = list(any) + default = ["a", "b", "c"] +} + +resource "azurerm_storage_container" "container02" { + for_each = toset(var.containersuffixlist) + name = "${var.containername}-${each.key}" + storage_account_name = azurerm_storage_account.this.name + container_access_type = "blob" +} \ No newline at end of file diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-04/terraform.tf b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-04/terraform.tf new file mode 100644 index 0000000000..21f1daeb1f --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-04/terraform.tf @@ -0,0 +1,28 @@ +# Assumption is you will be using az cli authentication +terraform { + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = ">=3.0.0" + } + random = { + source = "hashicorp/random" + } + } + backend "azurerm" { + resource_group_name = "tfstate-lnc01" + storage_account_name = "tfstatelnc01" + container_name = "tfstate" + key = "terraform.tfstate" + } +} + +# Configure the Microsoft Azure Provider +provider "azurerm" { + features { + key_vault { + purge_soft_delete_on_destroy = true + recover_soft_deleted_key_vaults = true + } + } +} \ No newline at end of file diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-04/terraform.tfvars b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-04/terraform.tfvars new file mode 100644 index 0000000000..202b282579 --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-04/terraform.tfvars @@ -0,0 +1,4 @@ +# Yes, this example still refereces CH01. If you change it, the resources will be re-created. +rgname = "ch01rg" +location = "WestUS3" +saname = "ch01lnc01" \ No newline at end of file diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-04/variables.tf b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-04/variables.tf new file mode 100644 index 0000000000..d8970332d1 --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-04/variables.tf @@ -0,0 +1,25 @@ +# Variables +variable "rgname" { + type = string +} +variable "location" { + type = string +} +variable "saname" { + type = string +} + +variable "geoRedundancy" { + type = bool + default = false +} + +variable "containername" { + type = string + default = "mycontainer" +} + +variable "vaultnameprefix" { + type = string + default = "mykv" +} diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-05/.gitignore b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-05/.gitignore new file mode 100644 index 0000000000..f7082f5225 --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-05/.gitignore @@ -0,0 +1 @@ +mysshkey diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-05/challenge-05.sh b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-05/challenge-05.sh new file mode 100644 index 0000000000..911683c05d --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-05/challenge-05.sh @@ -0,0 +1,9 @@ +# If self-deploying the challenges, recommend adding a prefix or suffix to Azure resources. +# For example, resourceGroupName = "-challenge-01-rg" + +terraform init +terraform validate +terraform plan +terraform output + + diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-05/kv.tf b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-05/kv.tf new file mode 100644 index 0000000000..776d19f0f0 --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-05/kv.tf @@ -0,0 +1,56 @@ +data "azurerm_client_config" "current" {} +data "azuread_client_config" "current" {} + +output "aadobject_id" { + value = data.azuread_client_config.current.object_id +} + +output "azrmobject_id" { + value = data.azurerm_client_config.current.object_id +} + +variable "kv_sku_name" { + type = string + description = "The SKU of the vault to be created." + default = "standard" +} + +variable "secret_permissions" { + type = list(string) + description = "List of secret permissions." + default = ["Set", "Get", "List", "Delete"] +} + +resource "azurerm_key_vault" "vault" { + name = "${var.vaultnameprefix}${random_string.suffix.result}" + resource_group_name = azurerm_resource_group.tfchallenge.name + location = azurerm_resource_group.tfchallenge.location + tenant_id = data.azurerm_client_config.current.tenant_id + sku_name = var.kv_sku_name + soft_delete_retention_days = 7 + + timeouts { + create = "5m" + delete = "5m" + } + + access_policy { + tenant_id = data.azurerm_client_config.current.tenant_id + // object_id = data.external.user.result.id + object_id = data.azuread_client_config.current.object_id + + secret_permissions = var.secret_permissions + } +} + +resource "random_password" "password" { + length = 16 + special = true +} + +resource "azurerm_key_vault_secret" "thissecret" { + key_vault_id = azurerm_key_vault.vault.id + name = "mysecret" + value = random_password.password.result + +} \ No newline at end of file diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-05/main05.tf b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-05/main05.tf new file mode 100644 index 0000000000..74ff8b72b0 --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-05/main05.tf @@ -0,0 +1,46 @@ + +# Resources +resource "random_string" "suffix" { + length = 4 + special = false + upper = false +} + +resource "azurerm_resource_group" "tfchallenge" { + name = var.rgname + location = var.location +} + +resource "azurerm_storage_account" "this" { + name = "${var.saname}${random_string.suffix.result}" + resource_group_name = azurerm_resource_group.tfchallenge.name + location = azurerm_resource_group.tfchallenge.location + account_tier = "Standard" + account_replication_type = var.geoRedundancy ? "GRS" : "LRS" +} + +resource "azurerm_storage_container" "thiscontainer" { + name = var.containername + storage_account_name = azurerm_storage_account.this.name + container_access_type = "blob" +} + +resource "azurerm_storage_container" "container01" { + count = 3 + + name = "${var.containername}-${count.index}" + storage_account_name = azurerm_storage_account.this.name + container_access_type = "blob" +} + +variable "containersuffixlist" { + type = list(any) + default = ["a", "b", "c"] +} + +resource "azurerm_storage_container" "container02" { + for_each = toset(var.containersuffixlist) + name = "${var.containername}-${each.key}" + storage_account_name = azurerm_storage_account.this.name + container_access_type = "blob" +} \ No newline at end of file diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-05/terraform.tf b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-05/terraform.tf new file mode 100644 index 0000000000..21f1daeb1f --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-05/terraform.tf @@ -0,0 +1,28 @@ +# Assumption is you will be using az cli authentication +terraform { + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = ">=3.0.0" + } + random = { + source = "hashicorp/random" + } + } + backend "azurerm" { + resource_group_name = "tfstate-lnc01" + storage_account_name = "tfstatelnc01" + container_name = "tfstate" + key = "terraform.tfstate" + } +} + +# Configure the Microsoft Azure Provider +provider "azurerm" { + features { + key_vault { + purge_soft_delete_on_destroy = true + recover_soft_deleted_key_vaults = true + } + } +} \ No newline at end of file diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-05/terraform.tfvars b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-05/terraform.tfvars new file mode 100644 index 0000000000..202b282579 --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-05/terraform.tfvars @@ -0,0 +1,4 @@ +# Yes, this example still refereces CH01. If you change it, the resources will be re-created. +rgname = "ch01rg" +location = "WestUS3" +saname = "ch01lnc01" \ No newline at end of file diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-05/variables.tf b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-05/variables.tf new file mode 100644 index 0000000000..564cc3ebfb --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-05/variables.tf @@ -0,0 +1,30 @@ +# Variables +variable "rgname" { + type = string +} +variable "location" { + type = string +} +variable "saname" { + type = string +} + +variable "geoRedundancy" { + type = bool + default = false +} + +variable "containername" { + type = string + default = "mycontainer" +} + +variable "vaultnameprefix" { + type = string + default = "mykv" +} + +variable "vmname" { + type = string + default = "myVM" +} \ No newline at end of file diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-05/vm.tf b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-05/vm.tf new file mode 100644 index 0000000000..e079a0a9fa --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-05/vm.tf @@ -0,0 +1,138 @@ + +# Create virtual network +resource "azurerm_virtual_network" "this" { + name = "myVnet" + address_space = ["10.0.0.0/16"] + location = azurerm_resource_group.tfchallenge.location + resource_group_name = azurerm_resource_group.tfchallenge.name +} + +# Create subnet +resource "azurerm_subnet" "vmsubnet" { + name = "vmSubnet" + resource_group_name = azurerm_resource_group.tfchallenge.name + virtual_network_name = azurerm_virtual_network.this.name + address_prefixes = ["10.0.1.0/24"] +} + + +# Create public IPs +resource "azurerm_public_ip" "vm" { + name = "vmPublicIP" + location = azurerm_resource_group.tfchallenge.location + resource_group_name = azurerm_resource_group.tfchallenge.name + allocation_method = "Dynamic" +} + +# Create Network Security Group and rule +resource "azurerm_network_security_group" "vm_nsg" { + name = "vmnsg" + location = azurerm_resource_group.tfchallenge.location + resource_group_name = azurerm_resource_group.tfchallenge.name + + security_rule { + name = "SSH" + priority = 1001 + direction = "Inbound" + access = "Allow" + protocol = "Tcp" + source_port_range = "*" + destination_port_range = "22" + source_address_prefix = "*" + destination_address_prefix = "*" + } +} + +# Create network interface +resource "azurerm_network_interface" "vm_nic" { + name = "vmNIC" + location = azurerm_resource_group.tfchallenge.location + resource_group_name = azurerm_resource_group.tfchallenge.name + + ip_configuration { + name = "vm_nic_configuration" + subnet_id = azurerm_subnet.vmsubnet.id + private_ip_address_allocation = "Dynamic" + public_ip_address_id = azurerm_public_ip.vm.id + } +} + +# Connect the security group to the network interface +# resource "azurerm_network_interface_security_group_association" "nic2nsg" { +# network_interface_id = azurerm_network_interface.vm_nic.id +# network_security_group_id = azurerm_network_security_group.vm_nsg.id +# } + +resource "azurerm_subnet_network_security_group_association" "subnet2nsg" { + subnet_id = azurerm_subnet.vmsubnet.id + network_security_group_id = azurerm_network_security_group.vm_nsg.id +} + + +# Create (and display) an SSH key +resource "tls_private_key" "example_ssh" { + algorithm = "RSA" + rsa_bits = 4096 +} + +resource "local_sensitive_file" "ssh_private_key" { + content = tls_private_key.example_ssh.private_key_pem + filename = "${path.module}/mysshkey" +} + +# Create virtual machine +resource "azurerm_linux_virtual_machine" "my_terraform_vm" { + name = var.vmname + location = azurerm_resource_group.tfchallenge.location + resource_group_name = azurerm_resource_group.tfchallenge.name + network_interface_ids = [azurerm_network_interface.vm_nic.id] + size = "Standard_DS1_v2" + + os_disk { + name = "myOsDisk" + caching = "ReadWrite" + storage_account_type = "Premium_LRS" + } + + source_image_reference { + publisher = "Canonical" + offer = "0001-com-ubuntu-server-jammy" + sku = "22_04-lts-gen2" + version = "latest" + } + + computer_name = "myvm" + admin_username = "azureuser" + disable_password_authentication = true + + admin_ssh_key { + username = "azureuser" + public_key = tls_private_key.example_ssh.public_key_openssh + } + + boot_diagnostics { + storage_account_uri = "" # null value means use managed storage account + } +} + +# Put SSH private key in keyvault +resource "azurerm_key_vault_secret" "ssh_private_key" { + key_vault_id = azurerm_key_vault.vault.id + name = "sshprivatekey" + value = tls_private_key.example_ssh.private_key_pem + +} + +############# outputs ########################### +output "ssh_publickey" { + value = tls_private_key.example_ssh.public_key_openssh +} + +output "ssh_private_key" { + value = tls_private_key.example_ssh.private_key_pem + sensitive = true +} + +output "vm_public_ip_address" { + value = azurerm_linux_virtual_machine.my_terraform_vm.public_ip_address +} diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-06/.gitignore b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-06/.gitignore new file mode 100644 index 0000000000..f7082f5225 --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-06/.gitignore @@ -0,0 +1 @@ +mysshkey diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-06/challenge-06.sh b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-06/challenge-06.sh new file mode 100644 index 0000000000..911683c05d --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-06/challenge-06.sh @@ -0,0 +1,9 @@ +# If self-deploying the challenges, recommend adding a prefix or suffix to Azure resources. +# For example, resourceGroupName = "-challenge-01-rg" + +terraform init +terraform validate +terraform plan +terraform output + + diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-06/kv.tf b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-06/kv.tf new file mode 100644 index 0000000000..bb091ecb8f --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-06/kv.tf @@ -0,0 +1,56 @@ +data "azurerm_client_config" "current" {} +data "azuread_client_config" "current" {} + +output "aadobject_id" { + value = data.azuread_client_config.current.object_id +} + +output "azrmobject_id" { + value = data.azurerm_client_config.current.object_id +} + +variable "kv_sku_name" { + type = string + description = "The SKU of the vault to be created." + default = "standard" +} + +variable "secret_permissions" { + type = list(string) + description = "List of secret permissions." + default = ["Set", "Get", "List", "Delete", "Purge", "Recover"] +} + +resource "azurerm_key_vault" "vault" { + name = "${var.vaultnameprefix}${random_string.suffix.result}" + resource_group_name = azurerm_resource_group.tfchallenge.name + location = azurerm_resource_group.tfchallenge.location + tenant_id = data.azurerm_client_config.current.tenant_id + sku_name = var.kv_sku_name + soft_delete_retention_days = 7 + + timeouts { + create = "5m" + delete = "5m" + } + + access_policy { + tenant_id = data.azurerm_client_config.current.tenant_id + // object_id = data.external.user.result.id + object_id = data.azuread_client_config.current.object_id + + secret_permissions = var.secret_permissions + } +} + +resource "random_password" "password" { + length = 16 + special = true +} + +resource "azurerm_key_vault_secret" "thissecret" { + key_vault_id = azurerm_key_vault.vault.id + name = "mysecret" + value = random_password.password.result + +} \ No newline at end of file diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-06/main06.tf b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-06/main06.tf new file mode 100644 index 0000000000..d4a8d870b1 --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-06/main06.tf @@ -0,0 +1,58 @@ + +# Resources +resource "random_string" "suffix" { + length = 4 + special = false + upper = false +} + +resource "azurerm_resource_group" "tfchallenge" { + name = var.rgname + location = var.location +} +########################################################## +module "myvm" { + source = "./modules/vm" + + rg = azurerm_resource_group.tfchallenge.name + location = azurerm_resource_group.tfchallenge.location + vmname = var.vmname + admin_username = "azureuser" + ssh_publickey = tls_private_key.example_ssh.public_key_openssh + subnet_id = module.mynetwork.vmsubnetid +} + +module "mynetwork" { + source = "./modules/network" + + rg = azurerm_resource_group.tfchallenge.name + location = azurerm_resource_group.tfchallenge.location + vnet_name = "myvnet" + address_space = ["10.0.0.0/16"] + subnet_name = "myvmsubnet" + subnet_addr_prefix = ["10.0.1.0/24"] + +} + +##################################################### + + + +# Create (and display) an SSH key +resource "tls_private_key" "example_ssh" { + algorithm = "RSA" + rsa_bits = 4096 +} + +resource "local_sensitive_file" "ssh_private_key" { + content = tls_private_key.example_ssh.private_key_pem + filename = "${path.module}/mysshkey" +} + +# Put SSH private key in keyvault +resource "azurerm_key_vault_secret" "ssh_private_key" { + key_vault_id = azurerm_key_vault.vault.id + name = "sshprivatekey" + value = tls_private_key.example_ssh.private_key_pem + +} diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-06/modules/network/main.tf b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-06/modules/network/main.tf new file mode 100644 index 0000000000..7c31e51cdd --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-06/modules/network/main.tf @@ -0,0 +1,49 @@ +# Resources +resource "random_string" "suffix" { + length = 4 + special = false + upper = false +} + + +# Create virtual network +resource "azurerm_virtual_network" "this" { + name = var.vnet_name + address_space = var.address_space + location = var.location + resource_group_name = var.rg +} + +# Create subnet +resource "azurerm_subnet" "vmsubnet" { + name = var.subnet_name + resource_group_name = var.rg + virtual_network_name = azurerm_virtual_network.this.name + address_prefixes = var.subnet_addr_prefix +} + + +# Create Network Security Group and rule +resource "azurerm_network_security_group" "vm_nsg" { + name = "vmnsg${random_string.suffix.result}" + location = var.location + resource_group_name = var.rg + + security_rule { + name = "SSH" + priority = 1001 + direction = "Inbound" + access = "Allow" + protocol = "Tcp" + source_port_range = "*" + destination_port_range = "22" + source_address_prefix = "*" + destination_address_prefix = "*" + } +} + +resource "azurerm_subnet_network_security_group_association" "subnet2nsg" { + subnet_id = azurerm_subnet.vmsubnet.id + network_security_group_id = azurerm_network_security_group.vm_nsg.id +} + diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-06/modules/network/output.tf b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-06/modules/network/output.tf new file mode 100644 index 0000000000..3b6685f427 --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-06/modules/network/output.tf @@ -0,0 +1,3 @@ +output "vmsubnetid" { + value = azurerm_subnet.vmsubnet.id +} \ No newline at end of file diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-06/modules/network/variables.tf b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-06/modules/network/variables.tf new file mode 100644 index 0000000000..f1641d4521 --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-06/modules/network/variables.tf @@ -0,0 +1,18 @@ +variable "rg" { + type = string +} +variable "location" { + type = string +} +variable "vnet_name" { + type = string +} +variable "address_space" { + type = list(string) +} +variable "subnet_name" { + type = string +} +variable "subnet_addr_prefix" { + type = list(string) +} diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-06/modules/vm/main.tf b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-06/modules/vm/main.tf new file mode 100644 index 0000000000..2d6cf147cd --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-06/modules/vm/main.tf @@ -0,0 +1,64 @@ +# Resources +resource "random_string" "suffix" { + length = 4 + special = false + upper = false +} + +# Create public IP +resource "azurerm_public_ip" "vmpip" { + name = "vmPublicIP${random_string.suffix.result}" + location = var.location + resource_group_name = var.rg + allocation_method = "Dynamic" +} + +# Create network interface +resource "azurerm_network_interface" "vm_nic" { + name = "vmNIC${random_string.suffix.result}" + location = var.location + resource_group_name = var.rg + + ip_configuration { + name = "vm_nic_configuration" + subnet_id = var.subnet_id + private_ip_address_allocation = "Dynamic" + public_ip_address_id = azurerm_public_ip.vmpip.id + } +} + +# Create virtual machine +resource "azurerm_linux_virtual_machine" "my_terraform_vm" { + name = var.vmname + location = var.location + resource_group_name = var.rg + network_interface_ids = [azurerm_network_interface.vm_nic.id] + size = "Standard_DS1_v2" + + os_disk { + name = "myOsDisk${random_string.suffix.result}" + caching = "ReadWrite" + storage_account_type = "Premium_LRS" + } + + source_image_reference { + publisher = "Canonical" + offer = "0001-com-ubuntu-server-jammy" + sku = "22_04-lts-gen2" + version = "latest" + } + + computer_name = var.vmname + admin_username = var.admin_username + disable_password_authentication = true + + admin_ssh_key { + username = var.admin_username + public_key = var.ssh_publickey + } + + boot_diagnostics { + storage_account_uri = "" # null value means use managed storage account + } +} + diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-06/modules/vm/output.tf b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-06/modules/vm/output.tf new file mode 100644 index 0000000000..bfbe2c1fc7 --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-06/modules/vm/output.tf @@ -0,0 +1,4 @@ + +output "vm_public_ip_address" { + value = azurerm_linux_virtual_machine.my_terraform_vm.public_ip_address +} diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-06/modules/vm/variables.tf b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-06/modules/vm/variables.tf new file mode 100644 index 0000000000..f8628cd051 --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-06/modules/vm/variables.tf @@ -0,0 +1,23 @@ +variable "rg" { + type = string +} + +variable "location" { + type = string +} + +variable "vmname" { + type = string +} + +variable "admin_username" { + type = string +} + +variable "ssh_publickey" { + type = string +} + +variable "subnet_id" { + type = string +} \ No newline at end of file diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-06/output.tf b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-06/output.tf new file mode 100644 index 0000000000..1b777d6e91 --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-06/output.tf @@ -0,0 +1,3 @@ +output "vm_pip" { + value = module.myvm.vm_public_ip_address +} \ No newline at end of file diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-06/terraform.tf b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-06/terraform.tf new file mode 100644 index 0000000000..21f1daeb1f --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-06/terraform.tf @@ -0,0 +1,28 @@ +# Assumption is you will be using az cli authentication +terraform { + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = ">=3.0.0" + } + random = { + source = "hashicorp/random" + } + } + backend "azurerm" { + resource_group_name = "tfstate-lnc01" + storage_account_name = "tfstatelnc01" + container_name = "tfstate" + key = "terraform.tfstate" + } +} + +# Configure the Microsoft Azure Provider +provider "azurerm" { + features { + key_vault { + purge_soft_delete_on_destroy = true + recover_soft_deleted_key_vaults = true + } + } +} \ No newline at end of file diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-06/terraform.tfvars b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-06/terraform.tfvars new file mode 100644 index 0000000000..202b282579 --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-06/terraform.tfvars @@ -0,0 +1,4 @@ +# Yes, this example still refereces CH01. If you change it, the resources will be re-created. +rgname = "ch01rg" +location = "WestUS3" +saname = "ch01lnc01" \ No newline at end of file diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-06/variables.tf b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-06/variables.tf new file mode 100644 index 0000000000..564cc3ebfb --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-06/variables.tf @@ -0,0 +1,30 @@ +# Variables +variable "rgname" { + type = string +} +variable "location" { + type = string +} +variable "saname" { + type = string +} + +variable "geoRedundancy" { + type = bool + default = false +} + +variable "containername" { + type = string + default = "mycontainer" +} + +variable "vaultnameprefix" { + type = string + default = "mykv" +} + +variable "vmname" { + type = string + default = "myVM" +} \ No newline at end of file diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-07/challenge-07.sh b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-07/challenge-07.sh new file mode 100644 index 0000000000..911683c05d --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-07/challenge-07.sh @@ -0,0 +1,9 @@ +# If self-deploying the challenges, recommend adding a prefix or suffix to Azure resources. +# For example, resourceGroupName = "-challenge-01-rg" + +terraform init +terraform validate +terraform plan +terraform output + + diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-07/disabled/kv.tf b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-07/disabled/kv.tf new file mode 100644 index 0000000000..bb091ecb8f --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-07/disabled/kv.tf @@ -0,0 +1,56 @@ +data "azurerm_client_config" "current" {} +data "azuread_client_config" "current" {} + +output "aadobject_id" { + value = data.azuread_client_config.current.object_id +} + +output "azrmobject_id" { + value = data.azurerm_client_config.current.object_id +} + +variable "kv_sku_name" { + type = string + description = "The SKU of the vault to be created." + default = "standard" +} + +variable "secret_permissions" { + type = list(string) + description = "List of secret permissions." + default = ["Set", "Get", "List", "Delete", "Purge", "Recover"] +} + +resource "azurerm_key_vault" "vault" { + name = "${var.vaultnameprefix}${random_string.suffix.result}" + resource_group_name = azurerm_resource_group.tfchallenge.name + location = azurerm_resource_group.tfchallenge.location + tenant_id = data.azurerm_client_config.current.tenant_id + sku_name = var.kv_sku_name + soft_delete_retention_days = 7 + + timeouts { + create = "5m" + delete = "5m" + } + + access_policy { + tenant_id = data.azurerm_client_config.current.tenant_id + // object_id = data.external.user.result.id + object_id = data.azuread_client_config.current.object_id + + secret_permissions = var.secret_permissions + } +} + +resource "random_password" "password" { + length = 16 + special = true +} + +resource "azurerm_key_vault_secret" "thissecret" { + key_vault_id = azurerm_key_vault.vault.id + name = "mysecret" + value = random_password.password.result + +} \ No newline at end of file diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-07/main07.tf b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-07/main07.tf new file mode 100644 index 0000000000..3dc996cfd5 --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-07/main07.tf @@ -0,0 +1,83 @@ + +# Resources +resource "random_string" "suffix" { + length = 4 + special = false + upper = false +} + +resource "azurerm_resource_group" "tfchallenge" { + name = var.rgname + location = var.location +} +####################################### + +# A log analytics workspace is required for container app environments +resource "azurerm_log_analytics_workspace" "thislaw" { + name = var.lawname + resource_group_name = azurerm_resource_group.tfchallenge.name + location = azurerm_resource_group.tfchallenge.location + sku = "PerGB2018" + retention_in_days = 30 +} + +resource "azurerm_container_app_environment" "this" { + name = "my-aca-environment" + resource_group_name = azurerm_resource_group.tfchallenge.name + location = azurerm_resource_group.tfchallenge.location + log_analytics_workspace_id = azurerm_log_analytics_workspace.thislaw.id +} +resource "azurerm_container_app" "myapp" { + name = "example-app" + container_app_environment_id = azurerm_container_app_environment.this.id + resource_group_name = azurerm_resource_group.tfchallenge.name + revision_mode = "Single" + ingress { + external_enabled = true + transport = "auto" + target_port = 80 +traffic_weight { + percentage = 100 + latest_revision = true +} + } + + template { + container { + name = "examplecontainerapp" + image = "mcr.microsoft.com/azuredocs/containerapps-helloworld:latest" + cpu = 0.25 + memory = "0.5Gi" + } + } +} + +output "containerfqdn" { + value = azurerm_container_app.myapp.latest_revision_fqdn +} +output "containername" { + value = azurerm_container_app.myapp.latest_revision_name +} + +##################################################### + + + +# # Create (and display) an SSH key +# resource "tls_private_key" "example_ssh" { +# algorithm = "RSA" +# rsa_bits = 4096 +# } + +# resource "local_sensitive_file" "ssh_private_key" { +# content = tls_private_key.example_ssh.private_key_pem +# filename = "${path.module}/mysshkey" +# } + +# # Put SSH private key in keyvault +# resource "azurerm_key_vault_secret" "ssh_private_key" { +# key_vault_id = azurerm_key_vault.vault.id +# name = "sshprivatekey" +# value = tls_private_key.example_ssh.private_key_pem + +# } diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-07/output.tf b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-07/output.tf new file mode 100644 index 0000000000..e69de29bb2 diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-07/terraform.tf b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-07/terraform.tf new file mode 100644 index 0000000000..a4b61b5f5f --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-07/terraform.tf @@ -0,0 +1,28 @@ +# Assumption is you will be using az cli authentication +terraform { + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = ">=3.0.0" + } + random = { + source = "hashicorp/random" + } + } + backend "azurerm" { + resource_group_name = "tfstate-lnc01" + storage_account_name = "tfstatelnc01" + container_name = "tfstate" + key = "terraform07.tfstate" + } +} + +# Configure the Microsoft Azure Provider +provider "azurerm" { + features { + key_vault { + purge_soft_delete_on_destroy = true + recover_soft_deleted_key_vaults = true + } + } +} \ No newline at end of file diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-07/terraform.tfvars b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-07/terraform.tfvars new file mode 100644 index 0000000000..2c767ef2d8 --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-07/terraform.tfvars @@ -0,0 +1,4 @@ +# Yes, this example still refereces CH01. If you change it, the resources will be re-created. +rgname = "ch07rg" +location = "WestUS3" +saname = "ch07lnc01" \ No newline at end of file diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-07/variables.tf b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-07/variables.tf new file mode 100644 index 0000000000..4dee11d4b5 --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-07/variables.tf @@ -0,0 +1,37 @@ +# Variables +variable "rgname" { + type = string +} +variable "location" { + type = string +} +variable "saname" { + type = string +} + +variable "geoRedundancy" { + type = bool + default = false +} + +variable "containername" { + type = string + default = "mycontainer" +} + +variable "vaultnameprefix" { + type = string + default = "mykv" +} + +variable "vmname" { + type = string + default = "myVM" +} + +variable "lawname" { + type = string + default = "mylaw" +} + + diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-08/acr/challenge-08-acr.sh b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-08/acr/challenge-08-acr.sh new file mode 100644 index 0000000000..911683c05d --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-08/acr/challenge-08-acr.sh @@ -0,0 +1,9 @@ +# If self-deploying the challenges, recommend adding a prefix or suffix to Azure resources. +# For example, resourceGroupName = "-challenge-01-rg" + +terraform init +terraform validate +terraform plan +terraform output + + diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-08/acr/main08acr.tf b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-08/acr/main08acr.tf new file mode 100644 index 0000000000..c2ecb8292f --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-08/acr/main08acr.tf @@ -0,0 +1,35 @@ + +# Resources +resource "random_string" "suffix" { + length = 4 + special = false + upper = false +} + +resource "azurerm_resource_group" "tfchallenge08acr" { + name = var.rgname + location = var.location +} + + +resource "azurerm_container_registry" "acr" { + name = "${var.acrname}${random_string.suffix.result}" + resource_group_name = azurerm_resource_group.tfchallenge08acr.name + location = azurerm_resource_group.tfchallenge08acr.location + sku = "Standard" + admin_enabled = true + +} + +variable "imagenames" { + type = list(string) + default = ["erjosito/yadaweb:1.0", "erjosito/yadaapi:1.0"] +} +module "importimage" { + count = length(var.imagenames) + + source = "github.com/onemtc/terraform-wth/modules/importimage" + // source = "../../../../modules/importimage" + acrid = azurerm_container_registry.acr.id + imagename = var.imagenames[count.index] +} diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-08/acr/terraform.tf b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-08/acr/terraform.tf new file mode 100644 index 0000000000..8b854c50cf --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-08/acr/terraform.tf @@ -0,0 +1,32 @@ +# Assumption is you will be using az cli authentication +terraform { + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = ">=3.0.0" + } + random = { + source = "hashicorp/random" + } + + azapi = { + source = "azure/azapi" + } + } + backend "azurerm" { + resource_group_name = "tfstate-lnc01" + storage_account_name = "tfstatelnc01" + container_name = "tfstate" + key = "terraform08acr.tfstate" + } +} + +# Configure the Microsoft Azure Provider +provider "azurerm" { + features { + key_vault { + purge_soft_delete_on_destroy = true + recover_soft_deleted_key_vaults = true + } + } +} \ No newline at end of file diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-08/acr/terraform.tfvars b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-08/acr/terraform.tfvars new file mode 100644 index 0000000000..e29268b1c7 --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-08/acr/terraform.tfvars @@ -0,0 +1,3 @@ +# Yes, this example still refereces CH01. If you change it, the resources will be re-created. +rgname = "ch08acr-rg" +location = "WestUS3" diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-08/acr/variables.tf b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-08/acr/variables.tf new file mode 100644 index 0000000000..e74fad76a6 --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-08/acr/variables.tf @@ -0,0 +1,14 @@ +# Variables +variable "rgname" { + type = string +} +variable "location" { + type = string +} + + +variable "acrname" { + type = string + default = "myregistry" +} + diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-08/challenge-08.sh b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-08/challenge-08.sh new file mode 100644 index 0000000000..911683c05d --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-08/challenge-08.sh @@ -0,0 +1,9 @@ +# If self-deploying the challenges, recommend adding a prefix or suffix to Azure resources. +# For example, resourceGroupName = "-challenge-01-rg" + +terraform init +terraform validate +terraform plan +terraform output + + diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-08/main08.tf b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-08/main08.tf new file mode 100644 index 0000000000..f2390eb8c7 --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-08/main08.tf @@ -0,0 +1,164 @@ + +# Resources +resource "random_string" "suffix" { + length = 4 + special = false + upper = false +} + +resource "azurerm_resource_group" "tfchallenge" { + name = var.rgname + location = var.location +} +####################################### + + +data "azurerm_container_registry" "myacr" { + name = var.acrname + resource_group_name = var.acrrg +} + + +# A log analytics workspace is required for container app environments +resource "azurerm_log_analytics_workspace" "thislaw" { + name = "${var.lawname}${random_string.suffix.result}" + resource_group_name = azurerm_resource_group.tfchallenge.name + location = azurerm_resource_group.tfchallenge.location + sku = "PerGB2018" + retention_in_days = 30 +} + +resource "azurerm_container_app_environment" "this" { + name = "my-aca-environment08" + resource_group_name = azurerm_resource_group.tfchallenge.name + location = azurerm_resource_group.tfchallenge.location + log_analytics_workspace_id = azurerm_log_analytics_workspace.thislaw.id +} + + +resource "azurerm_container_app" "web" { + name = "web" + container_app_environment_id = azurerm_container_app_environment.this.id + resource_group_name = azurerm_resource_group.tfchallenge.name + revision_mode = "Single" + ingress { + external_enabled = true + transport = "auto" + target_port = 80 + traffic_weight { + percentage = 100 + latest_revision = true + } + } + secret { + name = "regpwd" + value = data.azurerm_container_registry.myacr.admin_password + } + registry { + server = data.azurerm_container_registry.myacr.login_server + username = data.azurerm_container_registry.myacr.admin_username + password_secret_name = "regpwd" + } + template { + container { + name = "web" + image = "${data.azurerm_container_registry.myacr.login_server}/erjosito/yadaweb:1.0" + cpu = 0.25 + memory = "0.5Gi" + env { + name = "API_URL" + value = "https://${azurerm_container_app.api.latest_revision_fqdn}" + } + } + } +} + + +resource "azurerm_container_app" "api" { + name = "api" + container_app_environment_id = azurerm_container_app_environment.this.id + resource_group_name = azurerm_resource_group.tfchallenge.name + revision_mode = "Single" + ingress { + external_enabled = true + transport = "auto" + target_port = 8080 + traffic_weight { + percentage = 100 + latest_revision = true + } + } + secret { + name = "regpwd" + value = data.azurerm_container_registry.myacr.admin_password + } + secret { + name = "sqlpwd" + value = azurerm_mssql_server.this.administrator_login_password + } + registry { + server = data.azurerm_container_registry.myacr.login_server + username = data.azurerm_container_registry.myacr.admin_username + password_secret_name = "regpwd" + } + template { + container { + name = "api" + image = "${data.azurerm_container_registry.myacr.login_server}/erjosito/yadaapi:1.0" + cpu = 0.25 + memory = "0.5Gi" + env { + name = "SQL_SERVER_USERNAME" + value = azurerm_mssql_server.this.administrator_login + } + env { + name = "SQL_SERVER_FQDN" + value = azurerm_mssql_server.this.fully_qualified_domain_name + } + env { + name = "SQL_SERVER_PASSWORD" + secret_name = "sqlpwd" + } + } + } +} + +output "webfrontfqdn" { + value = azurerm_container_app.web.latest_revision_fqdn +} + +#################### + +resource "random_password" "password" { + length = 16 + special = true + numeric = true + min_numeric = 3 + min_lower = 3 + min_special = 3 + //override_special = ".-" +} + +resource "azurerm_mssql_server" "this" { + name = "sqlserver${random_string.suffix.result}" + resource_group_name = azurerm_resource_group.tfchallenge.name + location = azurerm_resource_group.tfchallenge.location + version = "12.0" + administrator_login = "adminuser" + administrator_login_password = random_password.password.result +} + +resource "azurerm_mssql_database" "this" { + name = "mydb" + server_id = azurerm_mssql_server.this.id + collation = "SQL_Latin1_General_CP1_CI_AS" + sku_name = "S0" + zone_redundant = false +} + +resource "azurerm_mssql_firewall_rule" "this" { + name = "FirewallRule1" + server_id = azurerm_mssql_server.this.id + start_ip_address = azurerm_container_app.api.outbound_ip_addresses[0] + end_ip_address = azurerm_container_app.api.outbound_ip_addresses[0] +} \ No newline at end of file diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-08/output.tf b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-08/output.tf new file mode 100644 index 0000000000..e69de29bb2 diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-08/terraform.tf b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-08/terraform.tf new file mode 100644 index 0000000000..a4b61b5f5f --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-08/terraform.tf @@ -0,0 +1,28 @@ +# Assumption is you will be using az cli authentication +terraform { + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = ">=3.0.0" + } + random = { + source = "hashicorp/random" + } + } + backend "azurerm" { + resource_group_name = "tfstate-lnc01" + storage_account_name = "tfstatelnc01" + container_name = "tfstate" + key = "terraform07.tfstate" + } +} + +# Configure the Microsoft Azure Provider +provider "azurerm" { + features { + key_vault { + purge_soft_delete_on_destroy = true + recover_soft_deleted_key_vaults = true + } + } +} \ No newline at end of file diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-08/terraform.tfvars b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-08/terraform.tfvars new file mode 100644 index 0000000000..2070bdcfdc --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-08/terraform.tfvars @@ -0,0 +1,2 @@ +rgname = "ch08rg" +location = "WestUS3" diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-08/variables.tf b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-08/variables.tf new file mode 100644 index 0000000000..a2b8619181 --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-08/variables.tf @@ -0,0 +1,22 @@ +# Variables +variable "rgname" { + type = string +} +variable "location" { + type = string +} + +variable "lawname" { + type = string + default = "mylaw" +} + +variable "acrname" { + type = string + default = "myregistry1l90" +} + +variable "acrrg" { + type = string + default = "ch08acr-rg" +} diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-09-wip/appgw.tf b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-09-wip/appgw.tf new file mode 100644 index 0000000000..5d87e12b46 --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-09-wip/appgw.tf @@ -0,0 +1,140 @@ +# Todo: +# refactor firewal_policy_id to use data source +resource "azurerm_public_ip" "appgwpip" { + name = "appgw-pip" + resource_group_name = azurerm_resource_group.tfchallenge.name + location = azurerm_resource_group.tfchallenge.location + allocation_method = "Static" + sku = "Standard" + domain_name_label = "yada${random_string.suffix.result}" +} + +resource "azurerm_virtual_network" "appgwvnet" { + name = "appgw-vnet" + resource_group_name = azurerm_resource_group.tfchallenge.name + location = azurerm_resource_group.tfchallenge.location + address_space = ["10.0.0.0/16"] + +} + +resource "azurerm_subnet" "appgwsubnet" { + name = "appgw-subnet" + resource_group_name = azurerm_resource_group.tfchallenge.name + virtual_network_name = azurerm_virtual_network.appgwvnet.name + address_prefixes = ["10.0.0.0/24"] +} + +resource "azurerm_web_application_firewall_policy" "res-0" { + name = "pol1" + resource_group_name = azurerm_resource_group.tfchallenge.name + location = azurerm_resource_group.tfchallenge.location + managed_rules { + managed_rule_set { + version = "3.2" + } + } + policy_settings { + mode = "Detection" + } +} + +resource "azurerm_application_gateway" "res-0" { + firewall_policy_id = azurerm_web_application_firewall_policy.res-0.id + + name = "ch09appgw" + resource_group_name = azurerm_resource_group.tfchallenge.name + location = azurerm_resource_group.tfchallenge.location + + + + autoscale_configuration { + max_capacity = 3 + min_capacity = 0 + } + backend_address_pool { + fqdns = [azurerm_container_app.api.latest_revision_fqdn] + name = "api-be" + } + backend_address_pool { + fqdns = [azurerm_container_app.web.latest_revision_fqdn] + name = "web-be" + } + backend_http_settings { + affinity_cookie_name = "ApplicationGatewayAffinity" + cookie_based_affinity = "Disabled" + name = "api-bes" + pick_host_name_from_backend_address = true + port = 443 + probe_name = "apiprobe" + protocol = "Https" + request_timeout = 20 + } + backend_http_settings { + affinity_cookie_name = "ApplicationGatewayAffinity" + cookie_based_affinity = "Disabled" + name = "web-bes" + pick_host_name_from_backend_address = true + port = 443 + protocol = "Https" + request_timeout = 20 + } + frontend_ip_configuration { + name = "appGwPublicFrontendIpIPv4" + public_ip_address_id = azurerm_public_ip.appgwpip.id + } + frontend_port { + name = "port_80" + port = 80 + } + + gateway_ip_configuration { + name = "appGatewayIpConfig" + subnet_id = azurerm_subnet.appgwsubnet.id + //subnet_id = "/subscriptions/1b2f6a87-f8a2-48d5-bfcf-23f8f3ffeab4/resourceGroups/ch09rg/providers/Microsoft.Network/virtualNetworks/wafvnet/subnets/default" + } + http_listener { + frontend_ip_configuration_name = "appGwPublicFrontendIpIPv4" + frontend_port_name = "port_80" + name = "mylistener" + protocol = "Http" + } + + probe { + interval = 30 + name = "apiprobe" + path = "/api/healthcheck" + pick_host_name_from_backend_http_settings = true + protocol = "Https" + timeout = 30 + unhealthy_threshold = 3 + match { + status_code = [] + } + } + request_routing_rule { + http_listener_name = "mylistener" + name = "mylistener-rule" + priority = 100 + rule_type = "PathBasedRouting" + url_path_map_name = "mylistener" + } + sku { + name = "WAF_v2" + tier = "WAF_v2" + } + url_path_map { + default_backend_address_pool_name = "web-be" + default_backend_http_settings_name = "web-bes" + name = "mylistener" + path_rule { + backend_address_pool_name = "api-be" + backend_http_settings_name = "api-bes" + name = "be-api-path" + paths = ["/api/*"] + } + } +} + +output "appgwurl" { + value = "http://${azurerm_public_ip.appgwpip.domain_name_label}.${azurerm_public_ip.appgwpip.location}.cloudapp.azure.com" +} \ No newline at end of file diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-09-wip/challenge-09.sh b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-09-wip/challenge-09.sh new file mode 100644 index 0000000000..911683c05d --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-09-wip/challenge-09.sh @@ -0,0 +1,9 @@ +# If self-deploying the challenges, recommend adding a prefix or suffix to Azure resources. +# For example, resourceGroupName = "-challenge-01-rg" + +terraform init +terraform validate +terraform plan +terraform output + + diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-09-wip/main09.tf b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-09-wip/main09.tf new file mode 100644 index 0000000000..75d475dde8 --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-09-wip/main09.tf @@ -0,0 +1,164 @@ + +# Resources +resource "random_string" "suffix" { + length = 4 + special = false + upper = false +} + +resource "azurerm_resource_group" "tfchallenge" { + name = var.rgname + location = var.location +} +####################################### + + +data "azurerm_container_registry" "myacr" { + name = var.acrname + resource_group_name = var.acrrg +} + + +# A log analytics workspace is required for container app environments +resource "azurerm_log_analytics_workspace" "thislaw" { + name = "${var.lawname}${random_string.suffix.result}" + resource_group_name = azurerm_resource_group.tfchallenge.name + location = azurerm_resource_group.tfchallenge.location + sku = "PerGB2018" + retention_in_days = 30 +} + +resource "azurerm_container_app_environment" "this" { + name = "my-aca-environment08" + resource_group_name = azurerm_resource_group.tfchallenge.name + location = azurerm_resource_group.tfchallenge.location + log_analytics_workspace_id = azurerm_log_analytics_workspace.thislaw.id +} + + +resource "azurerm_container_app" "web" { + name = "web" + container_app_environment_id = azurerm_container_app_environment.this.id + resource_group_name = azurerm_resource_group.tfchallenge.name + revision_mode = "Single" + ingress { + external_enabled = true + transport = "auto" + target_port = 80 + traffic_weight { + percentage = 100 + latest_revision = true + } + } + secret { + name = "regpwd" + value = data.azurerm_container_registry.myacr.admin_password + } + registry { + server = data.azurerm_container_registry.myacr.login_server + username = data.azurerm_container_registry.myacr.admin_username + password_secret_name = "regpwd" + } + template { + container { + name = "web" + image = "${data.azurerm_container_registry.myacr.login_server}/erjosito/yadaweb:1.0" + cpu = 0.25 + memory = "0.5Gi" + env { + name = "API_URL" + value = "https://${azurerm_container_app.api.latest_revision_fqdn}" + } + } + } +} + + +resource "azurerm_container_app" "api" { + name = "api" + container_app_environment_id = azurerm_container_app_environment.this.id + resource_group_name = azurerm_resource_group.tfchallenge.name + revision_mode = "Single" + ingress { + external_enabled = true + transport = "auto" + target_port = 8080 + traffic_weight { + percentage = 100 + latest_revision = true + } + } + secret { + name = "regpwd" + value = data.azurerm_container_registry.myacr.admin_password + } + secret { + name = "sqlpwd" + value = azurerm_mssql_server.this.administrator_login_password + } + registry { + server = data.azurerm_container_registry.myacr.login_server + username = data.azurerm_container_registry.myacr.admin_username + password_secret_name = "regpwd" + } + template { + container { + name = "api" + image = "${data.azurerm_container_registry.myacr.login_server}/erjosito/yadaapi:1.0" + cpu = 0.25 + memory = "0.5Gi" + env { + name = "SQL_SERVER_USERNAME" + value = azurerm_mssql_server.this.administrator_login + } + env { + name = "SQL_SERVER_FQDN" + value = azurerm_mssql_server.this.fully_qualified_domain_name + } + env { + name = "SQL_SERVER_PASSWORD" + secret_name = "sqlpwd" + } + } + } +} + +output "webfrontfqdn" { + value = azurerm_container_app.web.latest_revision_fqdn +} + +#################### + +resource "random_password" "password" { + length = 16 + special = true + numeric = true + min_numeric = 3 + min_lower = 3 + min_special = 3 + //override_special = ".-" +} + +resource "azurerm_mssql_server" "this" { + name = "sqlserver${random_string.suffix.result}" + resource_group_name = azurerm_resource_group.tfchallenge.name + location = azurerm_resource_group.tfchallenge.location + version = "12.0" + administrator_login = "adminuser" + administrator_login_password = random_password.password.result +} + +resource "azurerm_mssql_database" "this" { + name = "mydb" + server_id = azurerm_mssql_server.this.id + collation = "SQL_Latin1_General_CP1_CI_AS" + sku_name = "S0" + zone_redundant = false +} + +resource "azurerm_mssql_firewall_rule" "this" { + name = "FirewallRule1" + server_id = azurerm_mssql_server.this.id + start_ip_address = azurerm_container_app.api.outbound_ip_addresses[0] + end_ip_address = azurerm_container_app.api.outbound_ip_addresses[0] +} \ No newline at end of file diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-09-wip/output.tf b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-09-wip/output.tf new file mode 100644 index 0000000000..e69de29bb2 diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-09-wip/terraform.tf b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-09-wip/terraform.tf new file mode 100644 index 0000000000..a4b61b5f5f --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-09-wip/terraform.tf @@ -0,0 +1,28 @@ +# Assumption is you will be using az cli authentication +terraform { + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = ">=3.0.0" + } + random = { + source = "hashicorp/random" + } + } + backend "azurerm" { + resource_group_name = "tfstate-lnc01" + storage_account_name = "tfstatelnc01" + container_name = "tfstate" + key = "terraform07.tfstate" + } +} + +# Configure the Microsoft Azure Provider +provider "azurerm" { + features { + key_vault { + purge_soft_delete_on_destroy = true + recover_soft_deleted_key_vaults = true + } + } +} \ No newline at end of file diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-09-wip/terraform.tfvars b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-09-wip/terraform.tfvars new file mode 100644 index 0000000000..6d5782dd33 --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-09-wip/terraform.tfvars @@ -0,0 +1,2 @@ +rgname = "ch09rg" +location = "WestUS3" diff --git a/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-09-wip/variables.tf b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-09-wip/variables.tf new file mode 100644 index 0000000000..a2b8619181 --- /dev/null +++ b/012-InfraAsCode-Terraform/Coach/Solutions/Terraform-Challenge-09-wip/variables.tf @@ -0,0 +1,22 @@ +# Variables +variable "rgname" { + type = string +} +variable "location" { + type = string +} + +variable "lawname" { + type = string + default = "mylaw" +} + +variable "acrname" { + type = string + default = "myregistry1l90" +} + +variable "acrrg" { + type = string + default = "ch08acr-rg" +} diff --git a/012-InfraAsCode-Terraform/Student/Prerequisites/set_terraform.sh b/012-InfraAsCode-Terraform/Student/Prerequisites/set_terraform.sh deleted file mode 100644 index e1d354f677..0000000000 --- a/012-InfraAsCode-Terraform/Student/Prerequisites/set_terraform.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh -echo "Setting environment variables for Terraform" -export ARM_SUBSCRIPTION_ID=f86cXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX -export ARM_CLIENT_ID=b12cXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX -export ARM_CLIENT_SECRET=d1b7XXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX -export ARM_TENANT_ID=72f9XXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX - diff --git a/012-InfraAsCode-Terraform/Student/Terraform-Challenge-00.md b/012-InfraAsCode-Terraform/Student/Terraform-Challenge-00.md new file mode 100644 index 0000000000..b6f2ed56ce --- /dev/null +++ b/012-InfraAsCode-Terraform/Student/Terraform-Challenge-00.md @@ -0,0 +1,57 @@ +# Challenge 0: Pre-requisites - Ready, Set, GO + +**[Home](../README.md)** - [Next Challenge >](./Terraform-Challenge-01.md) + +## Introduction + +A smart cloud architect always has the right tools in their toolbox. + +## Description + +In this challenge, we'll be setting up all the tools we will need to complete our challenges. + +**Part 1: Pre-requisites** +- Install the recommended toolset: + - An [Azure Subscription](https://azure.microsoft.com/free/) + - _optional and not required_ [Windows Subsystem for Linux (Windows only)](https://learn.microsoft.com/windows/wsl/install) + - [Azure CLI](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli) + - [Terraform](https://developer.hashicorp.com/terraform/tutorials/azure-get-started/install-cli) + - [Visual Studio Code](https://code.visualstudio.com/) + - [Hashicorp Terraform extension for VS Code](https://marketplace.visualstudio.com/items?itemName=hashicorp.terraform) + - [Azure Terraform extension](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-azureterraform) + + +**Part 2: Hello World** + +1. Start VSCode and open a terminal window. Create a folder called 'hello-world' and cd into that folder. +2. Run `az login` to login to your Azure subscription. You might be prompted to open a browser window to complete the login process. +3. Open a new window in VSCode, and paste the following code into it: _(We're not going to explain this code yet, but we will in the next challenge. The purpose of this exercise is to validate that your tools are all working)_ + + ```hcl + terraform { + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = ">=3.0.0" + } + } + } + provider "azurerm" { + features {} + } + resource "azurerm_resource_group" "rg" { + name = "hello-world" // change this if needed + location = "eastus" + } + ``` +4. Save the file as `main.tf` in the `hello-world` folder. +5. In the terminal window, run `terraform init` to initialize the Terraform environment. +6. Run `terraform plan` to see what Terraform will do. +7. Run `terraform apply` to apply the changes. You will be prompted to confirm the changes. Type `yes` and press enter. +8. Run `terraform show` to see the resources that were created. +9. Run `terraform destroy` to destroy the resources. You will be prompted to confirm the changes. Type `yes` and press enter. + +## Success Criteria + +1. Your 'hello-world' deployment is successful. +2. Visual Studio Code extensions are installed. diff --git a/012-InfraAsCode-Terraform/Student/Terraform-Challenge-01.md b/012-InfraAsCode-Terraform/Student/Terraform-Challenge-01.md new file mode 100644 index 0000000000..584b3c23be --- /dev/null +++ b/012-InfraAsCode-Terraform/Student/Terraform-Challenge-01.md @@ -0,0 +1,46 @@ +# Challenge 1 - Basic Terraform + + [< Previous Challenge](./Terraform-Challenge-00.md) - [Home](../README.md) - [Next Challenge >](./Terraform-Challenge-02.md) + +## Pre-requisites + +Make sure your machine is set up with the proper tooling: [Prerequisites](./Terraform-Challenge-00.md) + +## Introduction + +The goals for this challenge include understanding: + +- Understanding Terraform basics: init, plan, apply, and state +- Setting up Terraform authentication with Azure +- How to author Terraform manifests using HCL + +In this challenge, you will create a simple Terraform manifest and deploy it to Azure. You will save Terraform state in an Azure Storage account + +## Challenge Part 1: Prepare to store Terraform State in Azure Storage + +Using the az cli, prepare an Azure storage account which will hold your terraform state + +**Learning Resources** +* [Store Terraform state in Azure Storage](https://learn.microsoft.com/en-us/azure/developer/terraform/store-state-in-azure-storage?tabs=azure-cli) + +## Challenge Part 2: Author a Terraform manifest that creates an Azure Storage Account + +Author a Terraform manifest that creates an Azure Storage Account, and returns the required outputs. The manifest(s): + +- Must save Terraform state in the storage account created in part 1 +- Must take inputs 1) `location` (eg, Azure region) 2) Resource group name 3) unique storage account name +- Must supply the required inputs via a _tfvars_ file +- The output must return the storage account id + +## Success Criteria + +1. Must meet above requirements and be able to demonstrate a full Terraform plan/apply sequence + +## Learning Resources + +- [Maintaining state using the `azurerm` (Azure storage) backend](https://developer.hashicorp.com/terraform/language/settings/backends/azurerm) +- [Azurerm Documentation (from Hashicorp)](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs) +- [Terraform on Azure (from Microsoft)](https://learn.microsoft.com/en-us/azure/developer/terraform/) +- [Authenticating using the Azure cli](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/guides/azure_cli) +- [Terraform Language Documentation](https://developer.hashicorp.com/terraform/language) +- [Terraform Variables](https://developer.hashicorp.com/terraform/language/values/variables) diff --git a/012-InfraAsCode-Terraform/Student/Terraform-Challenge-02.md b/012-InfraAsCode-Terraform/Student/Terraform-Challenge-02.md new file mode 100644 index 0000000000..fb0461ed09 --- /dev/null +++ b/012-InfraAsCode-Terraform/Student/Terraform-Challenge-02.md @@ -0,0 +1,41 @@ +# Challenge 2 - Terraform expressions and Referencing resources + +[< Previous Challenge](./Terraform-Challenge-01.md) - [Home](../README.md) - [Next Challenge >](./Terraform-Challenge-03.md) + +## Introduction + +In this challenge you will continue to modify and enhance the terraform manifest(s) created in Challenge 1. The goals for this challenge include: + ++ Understanding Terraform expressions ++ Using conditionals ++ Using string interpolation ++ Referencing other resources + +## Challenges + +**Challenge**: Refactor your code so that your Terraform configuration blocks (eg, terraform{}, provider "azurerm" {}, and variables) are in one file (eg, main.tf), and your Azure resources are in a separate file (eg, `azure.tf`), and outputs are in a third file (eg `outputs.tf`). _This is a general best practice for clarity_ + +**Challenge**: Use Terraform's [Random provider](https://registry.terraform.io/providers/hashicorp/random/latest/docs) to generate a four character suffix, and append this suffix to your storage account name (to ensure uniqueness). _(eg if your storage account name was `mystorageaccount`, the new storage account name would be (example) `mystorageaccountX5q3`)_ + +**Challenge**: If you haven't already done so, configure your storage account definition so that the `resource_group_name` and `location` properties are inherited from (eg, reference) the resource group definition. + +**Challenge**: Create an input variable named `geoRedundancy` of type `bool` and use the [conditional operator](https://developer.hashicorp.com/terraform/language/expressions/conditionals) to switch the storage account sku name between `GRS` & `LRS` depending on whether the parameter value is `true` or `false`, respectively. + +**Challenge**: Update the Terraform code to create a container in your storage account and modify the Terraform outputs to additionally show: + +- Storage Account Name +- Blob primary endpoint + + +## Success Criteria + +1. Your configuration and azure resource definitions are defined in separate files. +1. Your Storage Account is named using a random suffix. +1. You are able to select GRS or LRS storage via a input parameter +1. You can create blob container in your storage account + +## Learning Resources + ++ [Azurerm Documentation (from Hashicorp)](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs) ++ [Random provider](https://registry.terraform.io/providers/hashicorp/random/latest/docs) ++ [Conditional operator](https://developer.hashicorp.com/terraform/language/expressions/conditionals) diff --git a/012-InfraAsCode-Terraform/Student/Terraform-Challenge-03.md b/012-InfraAsCode-Terraform/Student/Terraform-Challenge-03.md new file mode 100644 index 0000000000..c7c3dfadd1 --- /dev/null +++ b/012-InfraAsCode-Terraform/Student/Terraform-Challenge-03.md @@ -0,0 +1,24 @@ +# Challenge 3 - Advanced resource declarations + +[< Previous Challenge](./Terraform-Challenge-02.md) - [Home](../README.md) - [Next Challenge >](./Terraform-Challenge-04.md) + +## Introduction + +The goals for this challenge include understanding: + +- How to create a set of resources based on a list or count (loops), eg iteration + +## Challenges + +**Challenge:** Using your existing Terraform manifests, create a new resource that will create additional blob containers in your existing storage account. + +- Create a string variable called `containernameprefix` and assign it a default value of your choice. +- Using the [count meta-argument](https://developer.hashicorp.com/terraform/language/meta-arguments/count), create a single blob container resource definition that provisions three containers, naming them _prefix-[count#]_ + +**Challenge:** Using your existing Terraform manifests, create a(nother) blob container, but rather than using the _count_ operator: +- Create a variable called `containersuffixlist` of type _list_ and have it contain the values `a`, `b`, and `c` +- Use the [for_each](https://developer.hashicorp.com/terraform/language/meta-arguments/for_each) operator in conjunction with a second blob container resource definition to create three more containers with the names _prefix_-a, _prefix_-b, and _prefix_-c. + +## Success Criteria + +1. Use the Azure portal or Azure cli to verify new containers were added to the storage account. diff --git a/012-InfraAsCode-Terraform/Student/Terraform-Challenge-04.md b/012-InfraAsCode-Terraform/Student/Terraform-Challenge-04.md new file mode 100644 index 0000000000..7e6c9574ae --- /dev/null +++ b/012-InfraAsCode-Terraform/Student/Terraform-Challenge-04.md @@ -0,0 +1,34 @@ +# Challenge 4 - Secret Values with Azure Key Vault + +[< Previous Challenge](./Terraform-Challenge-03.md) - [Home](../README.md) - [Next Challenge >](./Terraform-Challenge-05.md) + +## Introduction + +The goals for this challenge are to understand how to handle secret values, e.g., **Don't encode secrets in your code!** + +So far, the only parameters you have passed into your template have been related to storage accounts. In a later challenge, you will deploy resources requiring secret credentials as parameters. It is an **ANTI-pattern** to put a secret value such as a password in plain text in a parameter file! NEVER do this! + +It is a BEST practice to store secret values (such as passwords) in the Azure Key Vault service. + +## Description + +In this challenge, you will create an Azure Key Vault and store a secret in it. Then you will create a Bicep template & parameters file that reads from the key vault. + +## Challenges + ++ Create an Azure Key Vault using [azurerm_key_vault](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/key_vault) + + Note: Keyvaults require a unique name in Azure. Append your random suffix to the Keyvault name to ensure your name is unique. ++ Using the [azurerm_key_vault_key](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/key_vault_key) resource provider, create a key called `mysecret` with a [random password](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/password) and store it in the keyvault. ++ Explore the terraform state using the `terraform state list` and `terraform state show` commands to view the secret that was created + + Discuss with your coach: What are the implications of the secret being stored in Terraform's state file? + +## Success Criteria + +* Keyvault created +* Secret stored in the keyvault + + +## Suggested reading: + + [Create an Azure key vault and key using Terraform](https://learn.microsoft.com/en-us/azure/key-vault/keys/quick-create-terraform?tabs=azure-cli) + + diff --git a/012-InfraAsCode-Terraform/Student/Terraform-Challenge-05.md b/012-InfraAsCode-Terraform/Student/Terraform-Challenge-05.md new file mode 100644 index 0000000000..6e80360198 --- /dev/null +++ b/012-InfraAsCode-Terraform/Student/Terraform-Challenge-05.md @@ -0,0 +1,41 @@ +# Challenge 5 - Deploy a Virtual Machine + +[< Previous Challenge](./Terraform-Challenge-04.md) - [Home](../README.md) - [Next Challenge >](./Terraform-Challenge-06.md) + +## Introduction + +In this challenge, you will put all the pieces together and extend your Terraform manifests to deploy a Virtual Machine in Azure. + +The goals for this challenge include understanding: + ++ Globally unique naming context and complex dependencies ++ Clean code with neat parameter and variable values ++ Figuring out what Azure resources it takes to build a VM + +## Challenge + ++ Extend your Terraform to deploy a virtual machine: + + VM requirements: + + Linux OS + + Have terraform generate an SSH key and pass the public key to the VM. Store the private ssh key in the keyvault. + + Extra credit: write your ssh private key to a local file + + Use a resource prefix and template variables to have consistent naming of resources. + +## Success Criteria + +1. Verify that your virtual machine has been deployed via the Azure Portal or Azure CLI. +1. Connect to your virtual machine and verify you can login (Linux with SSH). (You will need to grab the ssh private key from the keyvault) + +## Tips + ++ It's up to you if you want to start with clean slate set of manifests or if you want to extend your current manifests to include a VM ++ Note that you will need to create a VNET, subnet, public IP, and NIC in addition to your VM. ++ You will need to open port 22 in your NSG to be able to ssh to the VM ++ You will need to supply your VM with a Public IP address or use the Azure Bastion service to connect to it. + +## Learning Resources + ++ [Quickstart: Use Terraform to create a Linux VM](https://learn.microsoft.com/en-us/azure/virtual-machines/linux/quick-create-terraform) ++ [azurerm_linux_virtual_machine](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/linux_virtual_machine) ++ [tls_private_key - used to create ssh keys](https://registry.terraform.io/providers/hashicorp/tls/latest/docs/resources/private_key) ++ [Virtual Machine - Azure Resource Manager reference](https://learn.microsoft.com/azure/templates/microsoft.compute/virtualmachines) diff --git a/012-InfraAsCode-Terraform/Student/Terraform-Challenge-06.md b/012-InfraAsCode-Terraform/Student/Terraform-Challenge-06.md new file mode 100644 index 0000000000..695121cfc9 --- /dev/null +++ b/012-InfraAsCode-Terraform/Student/Terraform-Challenge-06.md @@ -0,0 +1,39 @@ +# Challenge 6 - Terraform Modules + +[< Previous Challenge](./Terraform-Challenge-05.md) - [Home](../README.md) - [Next Challenge >](./Terraform-Challenge-07.md) + +## Introduction + +The goals for this challenge include understanding how Terraform modules allow for granular resource management and deployment, and support separation of duties. + +An application may require the composition of many underlying infrastructure resources in Azure. As you have now seen with just a single VM and its dependencies, a Terraform manifest can grow large rather quickly. + +Terraform supports the concept of [*modules*](https://developer.hashicorp.com/terraform/language/modules). When you write a Bicep file you can call another Bicep file as a module. When your template is transpiled into JSON, a single ARM template is produced including the code from your module(s). + +When templates get big, they become monoliths. They are hard to manage. By breaking your templates up into smaller modules, you can achieve more flexibility in how you manage your deployments. + +In many companies, deployment of cloud infrastructure may be managed by different teams. For example, a common network architecture and its security settings may be maintained by an operations team and shared across multiple application development teams. + +The network architecture and security groups are typically stable and do not change frequently. In contrast, application deployments that are deployed on the network may come and go. + +## Challenge + +In this challenge you will separate your existing Terraform manifests deployment into modules + +- Move the VM and its dependencies (VM, NIC, public-ip) into their own module. (eg move into a subdirectory). + - The module should take the following inputs: `resource group, location, vnname, admin username, ssh public key, subnet id` + - The module should output: `vm_public_ip_address` +- Move the vnet, subnet, and NSG definitions into their own module. The module should take the following parameters: + - `resource group, location, vnet name, address space, subnet name, subnet address prefix` + +By separating the networking resources into their own modules, an application team can test its infrastructure deployment in a test network. At a later point in time, the networking module can be replaced with a production module provided by the company's operations team. + +## Success Criteria + +1. Verify that all resources deploy as before when you had a single Bicep template. + +## Learning Resources + +- [Learn Terraform modules](https://developer.hashicorp.com/terraform/tutorials/modules/module) +- [Azure Terraform Verified Modules](https://github.com/Azure/terraform-azure-modules) + diff --git a/012-InfraAsCode-Terraform/Student/Terraform-Challenge-07.md b/012-InfraAsCode-Terraform/Student/Terraform-Challenge-07.md new file mode 100644 index 0000000000..6817a27a8e --- /dev/null +++ b/012-InfraAsCode-Terraform/Student/Terraform-Challenge-07.md @@ -0,0 +1,27 @@ +# Challenge 7 - Azure Container Apps (ACA) - Getting started + +[< Previous Challenge](./Terraform-Challenge-06.md) - [Home](../README.md) - [Next Challenge>](./Terraform-Challenge-08.md) + +## Introduction + +In this challenge, you will work with [Azure Container Apps (ACA)](https://learn.microsoft.com/en-us/azure/container-apps/overview), which is a fully managed environment that enables you to run microservices and containerized applications. + +Similar to Azure App Service, you will be deploying two components: + +- A *Container Apps Environment*, which is the "plan" or "hosting" component of the service +- An *Azure Container App*, which is the application itself + +It is recommended that you start fresh for this challenge and use a new set of Terraform resources (eg, new folder) & also use a new Terraform state file (eg, new key) + +## Challenges + ++ Deploy an [Azure Container Apps Environment](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/container_app_environment) using Terraform. + - You will be required to deploy a Log Analytics Workspace to support this ACA Environment ++ Deploy an [Azure Container App](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/container_app) based on the "hello-world" container `mcr.microsoft.com/azuredocs/containerapps-helloworld:latest` + - You will need to configure an ingress to be able to access this app from the outside (eg, Internet) ++ Define a Terraform output that shows the Container FQDN. + +## Success Criteria + +1. Verify you can view the web page hosted by the Azure Container App + diff --git a/012-InfraAsCode-Terraform/Student/Terraform-Challenge-08.md b/012-InfraAsCode-Terraform/Student/Terraform-Challenge-08.md new file mode 100644 index 0000000000..193be5a932 --- /dev/null +++ b/012-InfraAsCode-Terraform/Student/Terraform-Challenge-08.md @@ -0,0 +1,91 @@ +# Challenge 8 - Advanced Azure Container Apps (ACA) + +[< Previous Challenge](./Terraform-Challenge-07.md) - [Home](../README.md) + +## Introduction +In the prior challenge, we ran a very simple example of using ACA to host a hello-world app. + +In this challenge, we will expand on what we learned, and host a more complex three-tier application, exploring more capabilities of Azure Container Apps as well as Azure Container registry. This will mimic a real-world scenario where you are converting an imperative deployment script using the az cli to a set of declarative Terraform manifests. + +We will also explore the Terraform concept of "layered state files", where shared infrastructure components are deployed and managed separately from your application workloads + +## Challenges + +**Challenge Part 1**: In this first part of this challenge, we are going to deploy an Azure Container Registry (ACR) and and import some images to it. This ACR will be governed using a separate state file from the one we've been using for our other resources. This is a common pattern in Terraform, where you have shared infrastructure components that are deployed and managed separately from your application workloads. + +First, create a new sub-folder within your working directory (eg, `acr`) and cd into it. This will be used to host the code for your ACR definition. + +Next, within this folder, create the appropriate Terraform manifest definitions to deploy an [Azure Container Registry (ACR)](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/container_registry). ++ Deploy this to a different state file! You can use the existing Storage Account and Blob Container, but use a (new) different key from your existing state file. This will allow you to manage the ACR separately from the rest of your resources. ++ Be sure to enable the Admin user on the ACR. You will need this for part 2. + +We also need to import two container images into our ACR. There's no "official" way to do this using the standard terraform `azurerm` provider, so we are providing you a pre-authored module to use in your manifest. Add the following code to your manifest: + + +```hcl +variable "imagenames" { + type = list(string) + default = [ "erjosito/yadaweb:1.0", "erjosito/yadaapi:1.0" ] +} +module "importimage" { + count = length(var.imagenames) + source = "github.com/microsoft/WhatTheHack/012-InfraAsCode-Terraform/modules/importimage" + + imagename = var.imagenames[count.index] + acrid = azurerm_container_registry.acr.id // replace this with a reference to your ACR definition +} +``` + +***Success Criteria***: Verify that the ACR is deployed and that the images are imported. You can do this by logging into the Azure Portal and navigating to the ACR resource. You should see the images listed under the Repositories section. + +**Challenge Part 2**: Next, we will deploy a two-tier application to Azure Container Apps. This application will consist of a frontend web application, a backend API, and a SQL database. The application can be found in [this Github repo](https://github.com/microsoft/YADA). Specifically, there is already a script, available [here](https://github.com/microsoft/YADA/blob/main/deploy/ACA.md), that will deploy the application to Azure Container Apps. Your job is to take this example script and create a set of Terraform deployment manifests to deploy the application to your ACA environment. + +![Topology](https://github.com/microsoft/YADA/raw/main/web/app_arch.orig.png) + +Steps / Hints / Things to be aware of: + ++ Be sure you are using a different Terraform state file than you used in Part 1. Eg, be sure you have cd'd out of the `acr` folder and are back in the root of your current working directory. ++ Similar to the previous challenge (07), you'll need to create an [Azure Container Apps Environment](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/container_app_environment) using Terraform (and don't forget to deploy a Log Analytics Workspace to support this ACA Environment) ++ Deploy two [Azure Container Apps](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/container_app) from the container registry you created in the previous step. + - You will need to configure an ingress to be able to access the web app from the outside (eg, Internet) + - The api app should not be accessible from outside of the environment. + - You will need to appropriately set the environment variables for each app. Be sure to review the existing script to understand which variables need to be defined, abd be sure to review the hint below for the syntax of how to define environment variables in Terraform. Also review the readme page for each of the apps: + - [YADA Web](https://github.com/microsoft/YADA/blob/main/web/README.md) + - [YADA API](https://github.com/microsoft/YADA/blob/main/api/README.md) + - For your ACA app to be able to pull the images from your ACR, you will need to reference the ACR's adminuser & password in your container app definition. To do this, you will need to define the ACR as a Terraform `data` source. See [this example](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/container_registry) for more details. + ++ Deploy an [Azure SQL Server and an Azure SQL Database](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/mssql_database) to support the application. + - Use the Terraform Random Password provider to generate a password for the SQL Server. + - Be sure to configure a set of firewall rules to allow access from the ACA Environment. _Hint: You'll need to reference the outbound ip address of your API app_ + + +Hint: To define environment variables within the ACA definition in Terraform, you can use the following syntax: _(The Terraform docs are not very clear on how to use multiple env variables, so we are providing this hint to help you out)_ + +```hcl + template { + container { + env { + name = "varable1" + value = "value1" + } + env { + name = "varable2" + value = "value2" + } + [...] + } + } +``` + +## Success Criteria + +1. You can use your browser to access the web application. +2. The web application can successfully connect to the API. You can verify this by ensuring that the first block of text shows: + - Healthcheck: OK + - Shows the SQL version, eg `SQL Server version: Microsoft SQL Azure (RTM) - 12.0.2000.8 Mar 8 2023 17:58:50 Copyright (C) 2022 Microsoft Corporation` + - Shows connectivity info for application tier +3. API tier is not accessable from the Internet. + +Note that the links under `Direct Access to API` will not work. You would need to deploy an App Gateway to route those URIs properly. + + diff --git a/012-InfraAsCode-Terraform/Student/prerequisite.md b/012-InfraAsCode-Terraform/Student/prerequisite.md deleted file mode 100644 index b01d10ed63..0000000000 --- a/012-InfraAsCode-Terraform/Student/prerequisite.md +++ /dev/null @@ -1,49 +0,0 @@ -# Prerequisites for Terraform challenges - -## Install Terraform and configure it to access Azure - -Installation instructions can be found at the following URL - -https://docs.microsoft.com/en-us/azure/virtual-machines/linux/terraform-install-configure - - -## Create SSH Key - -Generate an SSH key pair. You will need this when you create your Linux VM. You can find a detailed instructions on how to create an SSH key pair at the URL below. - -https://docs.microsoft.com/en-us/azure/virtual-machines/linux/create-ssh-keys-detailed - -## Setup Terraform access to Azure - -Before you can enable Terraform to provision resources into Azure you will need to create a service principal. - -You can do this with the following Azure CLI commands: - -az account show --query "{subscriptionId:id, tenantId:tenantId}" -az account set --subscription="${SUBSCRIPTION_ID}" -az ad sp create-for-rbac --query '{"client_id": appId, "secret": password, "tenant": tenant}' - -You can either set environment variables or incorporate the values into your Terraform files. -```Bash -#!/bin/sh - -echo "Setting environment variables for Terraform" -export ARM_SUBSCRIPTION_ID=your_subscription_id -export ARM_CLIENT_ID=your_appId -export ARM_CLIENT_SECRET=your_password -export ARM_TENANT_ID=your_tenant_id -``` -OR -```json -provider "azurerm" { - subscription_id = "" - client_id = "" - client_secret = "" - tenant_id = "" -} -``` -## Install Packer - -Installation instructions can be found at the following URL - -https://www.packer.io/docs/install/index.html diff --git a/012-InfraAsCode-Terraform/Student/readme.md b/012-InfraAsCode-Terraform/Student/readme.md deleted file mode 100644 index fb40e5e107..0000000000 --- a/012-InfraAsCode-Terraform/Student/readme.md +++ /dev/null @@ -1,61 +0,0 @@ - -## Use Terraform to deploy Azure resources - -Terraform is a tool (templating language) for building, changing, and versioning infrastructure safely and efficiently. Using Terraform, you can automate the tasks of building, changing and de-provisioning the infrastructure - -## Challenge 1: Create a Resource Group -Create an Azure resource group using Terraform. It will hold all of the Azure resources you will use in subsequent challenges. You will need to run a few Terraform commands to do this like init, plan and apply. - -## Challenge 2: Create a Virtual Network -Create an Azure Virtual Network using Terraform. The virtual network should have an address space of 10.1.0.0/16 and be named "WTHVNetTF". Add one subnet to it with an address range of 10.1.0.0/24 and name it "default" - -## Challenge 3: Create a Network Security Group -Add a Network Security Group named WTHNSG with the following settings: -* Name: SSH -* Priority: 1001 -* Direction: Inbound -* Access: Allow -* Protocol: Tcp -* source_port_range: * -* destination_port_range: 22 -* source_address_prefix: * -* destination_address_prefix: * - -## Challenge 4: Put values into a separate variables file -So far you have been putting in your values directly into your Terraform configuration file. This is not usually a best practice. Instead of doing that create a separate Terraform variables file, put in the values you used in the prior challenge in there and reference those variables in the Terraform configuration file. - -## Challenge 5: Create an Ubuntu VM -Create an Ubuntu VM in Azure using Terraform. Use the latest version of Ubuntu. Its network card should be connected to the "default" subnet. Enable boot diagnostics for the VM. Use the SSH key you created in the prerequisites for authentication to the VM. Create a public IP Address for the VM. For security purposes it is recommended that your Network Security Group only allow your SSH's client public IP address. You can find your public IP address at or if you are using Azure CloudShell, you can do: -```bash -curl http://ifconfig.me -``` - -## Challenge 6: Use Packer to Create an Ubuntu image with NGINX installed - -In this challenge you will build a custom image that already has the NGINX web server already installed. You will need to build a Packer template JSON file. You should have downloaded Packer during the prerequisites section. In this template you define the builders and provisioners that do the build process. You will need to include the Azure service principal credentials (client_id, client_secret, and tenant_id) and Azure subscription_id that you used earlier. In addition to installing NGINX using apt, it would be a good idea to update the VM using apt. - -Once this is done you will need to build the Packer image which will create a custom Ubuntu image. - -Modify the Terraform configuration file you created in the last challenge to reference the Packer image instead. Add a Network Security Group to allow port 80. - -Test that NGINX is installed by opening your browser to the public IP address of the VM. You should see: - - Welcome to nginx! - If you see this page, the nginx web server is successfully installed and working. Further configuration is required. - - For online documentation and support please refer to nginx.org. - Commercial support is available at nginx.com. - -Thank you for using nginx. - -## References - -- Terraform Azure RM Provider - - - -- Terraform on Azure Documentation - - - - - - diff --git a/012-InfraAsCode-Terraform/modules/importimage/import.tf b/012-InfraAsCode-Terraform/modules/importimage/import.tf new file mode 100644 index 0000000000..9cf42726ac --- /dev/null +++ b/012-InfraAsCode-Terraform/modules/importimage/import.tf @@ -0,0 +1,36 @@ + +terraform { + required_providers { + azapi = { + source = "azure/azapi" + } + } +} + + +variable "acrid" { + type = string +} + +variable "imagename" { + type = string +} + + + + +resource "azapi_resource_action" "AcrImportImage" { + type = "Microsoft.ContainerRegistry/registries@2023-01-01-preview" + resource_id = var.acrid + response_export_values = ["*"] + action = "importImage" + method = "POST" + body = jsonencode({ + source = { + registryUri = "docker.io" + sourceImage = var.imagename + } + targetTags = [ var.imagename ] + mode = "Force" + }) +} \ No newline at end of file diff --git a/012-InfraAsCode-Terraform/readme.md b/012-InfraAsCode-Terraform/readme.md index 018e153321..a3c56ff744 100644 --- a/012-InfraAsCode-Terraform/readme.md +++ b/012-InfraAsCode-Terraform/readme.md @@ -1,58 +1,66 @@ -# What the Hack: Infrastructure as Code with Terraform +# What The Hack: Infrastructure As Code with Terraform + ## Introduction -DevOps is a journey not a destination. Implementing Infrastructure-as-Code is one of the first steps you will take on your DevOps journey! +DevOps is a journey not a destination. Implementing Infrastructure-as-Code is one of the first steps you will need to take! When implementing an application environment in the cloud, it is important to have a repeatable way to deploy the underlying infrastructure components as well as your software into the target environment. This includes resources such as: - Virtual Networks, Network Security Groups (Firewalls), Public IPs, Virtual Machines, Storage (Disks) -- PaaS Services (Azure SQL, App Service, etc) +- PaaS Services (Azure Container Apps, Azure SQL, App Service, etc) - Configuration Management (installing & configuring software on VMs) -The best way to make deployments repeatable is to define them with code, hence the term "Infrastructure as Code" (aka IAC). There are multiple technologies that enable you to define your IaC. Some of these include: -- Azure Resource Manager (ARM) Templates -- PowerShell Desired State Configuration (DSC) -- HashiCorp's Terraform & Packer +The best way to make deployments repeatable is to define them with code, hence the term "Infrastructure as Code" (aka IAC). There are multiple technologies that enable you to achieve this. Some of these include: +- ARM Templates +- Bicep Templates +- HashiCorp's Terraform - Ansible, Chef, Puppet, Salt Stack, and others -Terraform is a tool (templating language) for building, changing, and versioning infrastructure safely and efficiently. Using Terraform, you can automate the tasks of building, changing and de-provisioning the infrastructure - -This hack is focused on using Terraform to implement your IaC. It does not mean this is the only way to implement IaC. It is just one way amongst many. If you want to learn how to do IaC in Azure with other technologies, try one of our other IaC hacks for [ARM Templates](../011-InfraAsCode-ARM-DSC) or [Ansible](../013-InfraAsCode-Ansible/). - +This hack is focused on using Terraform to implement your IaC. ## Learning Objectives + This hack will help you learn: -- How Terraform works to deploy infrastructure in Azure -- How Terraform can be used to trigger the install of software on a VM - -## Challenges -0. [Get your machine ready](./Student/prerequisite.md) - - Configure Terraform on Linux subsystem, credentials -1. ["Hello World" Terraform](./Student/readme.md) - - Create an Azure resource group using Terraform -1. [Deploy a Virtual Network](./Student/readme.md) - - Learn how to find Terraform HCL syntax to deploy an Azure resource -1. [Open Some Ports](./Student/readme.md) - - Learn about variables, dependencies, idempotency -1. [Create a Linux Virtual Machine](./Student/readme.md) - - Learn what an Azure Virtual Machine is composed of -1. [Use Packer to Create a Linux image with NGINX installed](./Student/readme.md) - - Learn about custom build images with Packer +- How Terraform can be used to deploy Azure infrastructure -## Prerequisites -- Your own Azure subscription with Owner access -- Visual Studio Code -- Azure CLI -- Terraform +The challenges build upon each other incrementally. You will start by creating basic Terraform manifests to get you familiar with the tools & syntax. Then you extend your manifests incrementally to deploy multiple infrastructure resources to Azure. -## Repository Contents +### Challenges + +- Challenge 0: **[Pre-Requisites - Ready, Set, Go!](./Student/Terraform-Challenge-00.md)** + - Prepare your workstation to work with Azure & Terraform +- Challenge 1: **[Basic Terraform](./Student/Terraform-Challenge-01.md)** + - Develop a simple Terraform manifest that takes inputs to create an Azure Storage Account, and returns outputs +- Challenge 2: **[Terraform expressions and referencing resources](./Student/Terraform-Challenge-02.md)** + - Learn Terraform expressions, conditionals, and referencing resources +- Challenge 3: **[Advanced resource declarations](./Student/Terraform-Challenge-03.md)** + - Advanced resource declarations including iteration +- Challenge 4: **[Secret Values with Azure Key Vault](./Student/Terraform-Challenge-04.md)** + - Create and reference an Azure Key Vault +- Challenge 5: **[Deploy a Virtual Machine](./Student/Terraform-Challenge-05.md)** + - Create a complex deployment with multiple dependencies +- Challenge 6: **[Terraform Modules](./Student/Terraform-Challenge-06.md)** + - Learn how create reusable modules for granular resource management + - Challenge 7: **[Azure Container Apps (ACA)](./Student/Terraform-Challenge-07.md)** + - Create an ACA environment and deploy a simple `hello world` application to it + - Challenge 8: **[Advanced ACA](./Student/Terraform-Challenge-08.md)** + - Provision an Azure container registry, import images to it, then provision and deploy a multi-microservice (frontend and backend) containerized application -- `../Coach/Solutions` - - Complete solution files for each challenge -- `../Student` - - Terraform challenges -## Contributors -- Pete Rodriguez +## Prerequisites + +You will want to prepare your machine with the following to help complete the Challenges for this hack: + +* Azure Subscription +* _optional_ [Windows Subsystem for Linux (Windows 10-only)](https://docs.microsoft.com/en-us/windows/wsl/install-win10) +* [Azure CLI](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli) +* [Visual Studio Code](https://code.visualstudio.com/) + + +## Repository Contents +- `../Student` + - Terraform challenges +- `../Student/Resources` + - Shell scripts needed to complete the challenges From 218aba2a64f599248597a52a52943a16ce99c779 Mon Sep 17 00:00:00 2001 From: Pete Rodriguez Date: Fri, 12 May 2023 13:49:57 -0500 Subject: [PATCH 03/35] Update README.md --- 012-InfraAsCode-Terraform/Coach/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/012-InfraAsCode-Terraform/Coach/README.md b/012-InfraAsCode-Terraform/Coach/README.md index 7a61570128..6133491027 100644 --- a/012-InfraAsCode-Terraform/Coach/README.md +++ b/012-InfraAsCode-Terraform/Coach/README.md @@ -3,7 +3,7 @@ ## Introduction Welcome to the coach's guide for the Infrastructure As Code: Terraform What The Hack. Here you will find links to specific guidance for coaches for each of the challenges. -Also remember that this hack includes a optional [lecture presentation](tbd) that features short presentations to introduce key topics associated with each challenge. It is recommended that the host present each short presentation before attendees kick off that challenge. +Also remember that this hack includes an optional [lecture presentation](tbd) that features short presentations to introduce key topics associated with each challenge. It is recommended that the host present each short presentation before attendees kick off that challenge. **NOTE:** If you are a Hackathon participant, this is the answer guide. Don't cheat yourself by looking at these during the hack! Go learn something. :) From 1f202cd68d8a85db3cc18770e7186ff2672b104d Mon Sep 17 00:00:00 2001 From: Pete Rodriguez Date: Fri, 12 May 2023 13:53:11 -0500 Subject: [PATCH 04/35] Update Solution-00.md --- 012-InfraAsCode-Terraform/Coach/Solution-00.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/012-InfraAsCode-Terraform/Coach/Solution-00.md b/012-InfraAsCode-Terraform/Coach/Solution-00.md index 85d820c193..62aa44750d 100644 --- a/012-InfraAsCode-Terraform/Coach/Solution-00.md +++ b/012-InfraAsCode-Terraform/Coach/Solution-00.md @@ -21,7 +21,7 @@ If you've never used Azure, you will get: Details can be found here on [free services](https://azure.microsoft.com/en-us/free/). -If you have used Azure before, we will still try to limit cost of services by suspending, shutting down services, or destroy services before end of the hackathon. You will still be able to use the free services (up to their quotas) like App Service, or Functions. +If you have used Azure before, we will still try to limit cost of services by suspending, shutting down services, or destroying services before the end of the hackathon. You will still be able to use the free services (up to their quotas) like Azure App Service or Functions. ## Windows Subsystem for Linux @@ -63,7 +63,7 @@ The Azure CLI is a cross-platform command-line tool providing a great experience The Azure CLI will be the preferred (and supported) approach for this event, so please install the Azure CLI on your workstation. If you are not able to install the Azure CLI, or are using a workstation that is not your own, you can use the Azure CLI in the browser via the Azure Cloud Shell from the Azure Portal. -For Windows users, see the note below about how & where to install the Azure CLI! +For Windows users, see the note below about how and where to install the Azure CLI! - [Install on Windows](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli-windows?view=azure-cli-latest) @@ -126,4 +126,4 @@ This extension provides language support for Bicep and its language expressions. [**Bicep CLI**](https://github.com/Azure/bicep/blob/main/docs/installing.md) - Compiles Bicep files into ARM templates. Cross-platform. \ No newline at end of file + Compiles Bicep files into ARM templates. Cross-platform. From 3d2163770f6208296dfa66ba0a376099c79092e4 Mon Sep 17 00:00:00 2001 From: Pete Rodriguez Date: Fri, 12 May 2023 13:54:15 -0500 Subject: [PATCH 05/35] Update Solution-01.md --- 012-InfraAsCode-Terraform/Coach/Solution-01.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/012-InfraAsCode-Terraform/Coach/Solution-01.md b/012-InfraAsCode-Terraform/Coach/Solution-01.md index 263061e6c4..351eb41a07 100644 --- a/012-InfraAsCode-Terraform/Coach/Solution-01.md +++ b/012-InfraAsCode-Terraform/Coach/Solution-01.md @@ -6,4 +6,4 @@ This is the "Hello World" challenge. The goal is to deploy an Azure Storage Account to a targeted resource group. This storage account will be accessed again in Challenge 2. -If you are self-hosting, recommend to prefix your resources with your initials to avoid conflicts. +If you are self-hosting, it is recommended that you prefix your resources with your initials to avoid conflicts. From 59aa02a6b45337d8ac3b4a69800d1479a21d7b54 Mon Sep 17 00:00:00 2001 From: Pete Rodriguez Date: Fri, 12 May 2023 13:54:42 -0500 Subject: [PATCH 06/35] Update Solution-02.md --- 012-InfraAsCode-Terraform/Coach/Solution-02.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/012-InfraAsCode-Terraform/Coach/Solution-02.md b/012-InfraAsCode-Terraform/Coach/Solution-02.md index 15f15d08b5..c209c9f592 100644 --- a/012-InfraAsCode-Terraform/Coach/Solution-02.md +++ b/012-InfraAsCode-Terraform/Coach/Solution-02.md @@ -1,4 +1,4 @@ -# Challenge 2: Terraform Expressions and Referencing Resources - Coach's Guide +# Challenge 2: Terraform Expressions and Referencing Resources - Coach's Guide [< Previous Challenge](./Solution-01.md) - **[Home](./README.md)** - [Next Challenge >](./Solution-03.md) From 4323d59c5d53a2e159f2fbc9a7fa31e85b8df83b Mon Sep 17 00:00:00 2001 From: Pete Rodriguez Date: Fri, 12 May 2023 13:55:54 -0500 Subject: [PATCH 07/35] Update Solution-05.md --- 012-InfraAsCode-Terraform/Coach/Solution-05.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/012-InfraAsCode-Terraform/Coach/Solution-05.md b/012-InfraAsCode-Terraform/Coach/Solution-05.md index e3760c6cb9..6e25c91982 100644 --- a/012-InfraAsCode-Terraform/Coach/Solution-05.md +++ b/012-InfraAsCode-Terraform/Coach/Solution-05.md @@ -4,4 +4,4 @@ ## Notes & Guidance -Be aware that while the sample at https://learn.microsoft.com/en-us/azure/virtual-machines/linux/quick-create-terraform is very useful/helpful, it is not 100% aligned with our challenges. Eg, Be sure that the participants do not blindly cut/paste the samples without understanding what they do. +Be aware that while the sample at https://learn.microsoft.com/en-us/azure/virtual-machines/linux/quick-create-terraform is very useful/helpful, it is not 100% aligned with our challenges. Be sure that the participants do not blindly cut/paste the samples without understanding what they do. From 7e6ae4d6b275a9cadbac97b70dac790649593ac4 Mon Sep 17 00:00:00 2001 From: Pete Rodriguez Date: Fri, 12 May 2023 14:01:36 -0500 Subject: [PATCH 08/35] Update Terraform-Challenge-00.md --- 012-InfraAsCode-Terraform/Student/Terraform-Challenge-00.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/012-InfraAsCode-Terraform/Student/Terraform-Challenge-00.md b/012-InfraAsCode-Terraform/Student/Terraform-Challenge-00.md index b6f2ed56ce..83ef115839 100644 --- a/012-InfraAsCode-Terraform/Student/Terraform-Challenge-00.md +++ b/012-InfraAsCode-Terraform/Student/Terraform-Challenge-00.md @@ -1,6 +1,6 @@ # Challenge 0: Pre-requisites - Ready, Set, GO -**[Home](../README.md)** - [Next Challenge >](./Terraform-Challenge-01.md) +**[Home](../README.md)** - [Next Challenge >](./Challenge-01.md) ## Introduction From ad7cd012864c35cfb97be76cbe5044d136530d56 Mon Sep 17 00:00:00 2001 From: Pete Rodriguez Date: Fri, 12 May 2023 14:04:20 -0500 Subject: [PATCH 09/35] Update Terraform-Challenge-01.md --- .../Student/Terraform-Challenge-01.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/012-InfraAsCode-Terraform/Student/Terraform-Challenge-01.md b/012-InfraAsCode-Terraform/Student/Terraform-Challenge-01.md index 584b3c23be..6e1060a7ed 100644 --- a/012-InfraAsCode-Terraform/Student/Terraform-Challenge-01.md +++ b/012-InfraAsCode-Terraform/Student/Terraform-Challenge-01.md @@ -4,7 +4,7 @@ ## Pre-requisites -Make sure your machine is set up with the proper tooling: [Prerequisites](./Terraform-Challenge-00.md) +Make sure your machine is set up with the proper tooling: [Prerequisites](./Challenge-00.md) ## Introduction @@ -16,14 +16,16 @@ The goals for this challenge include understanding: In this challenge, you will create a simple Terraform manifest and deploy it to Azure. You will save Terraform state in an Azure Storage account -## Challenge Part 1: Prepare to store Terraform State in Azure Storage +## Description + +### Part 1: Prepare to store Terraform State in Azure Storage Using the az cli, prepare an Azure storage account which will hold your terraform state **Learning Resources** * [Store Terraform state in Azure Storage](https://learn.microsoft.com/en-us/azure/developer/terraform/store-state-in-azure-storage?tabs=azure-cli) -## Challenge Part 2: Author a Terraform manifest that creates an Azure Storage Account +### Part 2: Author a Terraform manifest that creates an Azure Storage Account Author a Terraform manifest that creates an Azure Storage Account, and returns the required outputs. The manifest(s): From 5b9af9095bd0fa7bc84c532e45a50a33d6c0d1af Mon Sep 17 00:00:00 2001 From: Pete Rodriguez Date: Fri, 12 May 2023 14:04:56 -0500 Subject: [PATCH 10/35] Update Terraform-Challenge-01.md --- 012-InfraAsCode-Terraform/Student/Terraform-Challenge-01.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/012-InfraAsCode-Terraform/Student/Terraform-Challenge-01.md b/012-InfraAsCode-Terraform/Student/Terraform-Challenge-01.md index 6e1060a7ed..b86661113a 100644 --- a/012-InfraAsCode-Terraform/Student/Terraform-Challenge-01.md +++ b/012-InfraAsCode-Terraform/Student/Terraform-Challenge-01.md @@ -1,6 +1,6 @@ # Challenge 1 - Basic Terraform - [< Previous Challenge](./Terraform-Challenge-00.md) - [Home](../README.md) - [Next Challenge >](./Terraform-Challenge-02.md) + [< Previous Challenge](./Challenge-00.md) - [Home](../README.md) - [Next Challenge >](./Challenge-02.md) ## Pre-requisites From 5642f1b90af67ec887b5eebd5d44107b5d01ec77 Mon Sep 17 00:00:00 2001 From: Pete Rodriguez Date: Fri, 12 May 2023 14:11:48 -0500 Subject: [PATCH 11/35] Update Terraform-Challenge-02.md --- .../Student/Terraform-Challenge-02.md | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/012-InfraAsCode-Terraform/Student/Terraform-Challenge-02.md b/012-InfraAsCode-Terraform/Student/Terraform-Challenge-02.md index fb0461ed09..444db1a26d 100644 --- a/012-InfraAsCode-Terraform/Student/Terraform-Challenge-02.md +++ b/012-InfraAsCode-Terraform/Student/Terraform-Challenge-02.md @@ -1,6 +1,6 @@ # Challenge 2 - Terraform expressions and Referencing resources -[< Previous Challenge](./Terraform-Challenge-01.md) - [Home](../README.md) - [Next Challenge >](./Terraform-Challenge-03.md) +[< Previous Challenge](./Challenge-01.md) - [Home](../README.md) - [Next Challenge >](./Challenge-03.md) ## Introduction @@ -11,17 +11,19 @@ In this challenge you will continue to modify and enhance the terraform manifest + Using string interpolation + Referencing other resources -## Challenges +## Description -**Challenge**: Refactor your code so that your Terraform configuration blocks (eg, terraform{}, provider "azurerm" {}, and variables) are in one file (eg, main.tf), and your Azure resources are in a separate file (eg, `azure.tf`), and outputs are in a third file (eg `outputs.tf`). _This is a general best practice for clarity_ +You will accomplish these tasks in this challenge: -**Challenge**: Use Terraform's [Random provider](https://registry.terraform.io/providers/hashicorp/random/latest/docs) to generate a four character suffix, and append this suffix to your storage account name (to ensure uniqueness). _(eg if your storage account name was `mystorageaccount`, the new storage account name would be (example) `mystorageaccountX5q3`)_ +1. Refactor your code so that your Terraform configuration blocks (eg, terraform{}, provider "azurerm" {}, and variables) are in one file (eg, main.tf), and your Azure resources are in a separate file (e.g., `azure.tf`), and outputs are in a third file (eg `outputs.tf`). _This is a general best practice for clarity_ -**Challenge**: If you haven't already done so, configure your storage account definition so that the `resource_group_name` and `location` properties are inherited from (eg, reference) the resource group definition. +1. Use Terraform's [Random provider](https://registry.terraform.io/providers/hashicorp/random/latest/docs) to generate a four character suffix, and append this suffix to your storage account name (to ensure uniqueness). _(e.g., if your storage account name was `mystorageaccount`, the new storage account name would be similar to `mystorageaccountX5q3`)_ -**Challenge**: Create an input variable named `geoRedundancy` of type `bool` and use the [conditional operator](https://developer.hashicorp.com/terraform/language/expressions/conditionals) to switch the storage account sku name between `GRS` & `LRS` depending on whether the parameter value is `true` or `false`, respectively. +1. If you haven't already done so, configure your storage account definition so that the `resource_group_name` and `location` properties are inherited from (that is, they reference) the resource group definition. -**Challenge**: Update the Terraform code to create a container in your storage account and modify the Terraform outputs to additionally show: +1. Create an input variable named `geoRedundancy` of type `bool` and use the [conditional operator](https://developer.hashicorp.com/terraform/language/expressions/conditionals) to switch the storage account SKU name between `GRS` & `LRS` depending on whether the parameter value is `true` or `false`, respectively. + +1. Update the Terraform code to create a container in your storage account and modify the Terraform outputs to additionally show: - Storage Account Name - Blob primary endpoint From cd9091ea3dfbf25a591071f184f5cb35cfcc33c8 Mon Sep 17 00:00:00 2001 From: Pete Rodriguez Date: Fri, 12 May 2023 14:14:43 -0500 Subject: [PATCH 12/35] Update Terraform-Challenge-03.md --- .../Student/Terraform-Challenge-03.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/012-InfraAsCode-Terraform/Student/Terraform-Challenge-03.md b/012-InfraAsCode-Terraform/Student/Terraform-Challenge-03.md index c7c3dfadd1..48c3852f93 100644 --- a/012-InfraAsCode-Terraform/Student/Terraform-Challenge-03.md +++ b/012-InfraAsCode-Terraform/Student/Terraform-Challenge-03.md @@ -8,17 +8,21 @@ The goals for this challenge include understanding: - How to create a set of resources based on a list or count (loops), eg iteration -## Challenges +## Description -**Challenge:** Using your existing Terraform manifests, create a new resource that will create additional blob containers in your existing storage account. +In this challenge, you will accomplish the following tasks: + +1. Using your existing Terraform manifests, create a new resource that will create additional blob containers in your existing storage account. - Create a string variable called `containernameprefix` and assign it a default value of your choice. - Using the [count meta-argument](https://developer.hashicorp.com/terraform/language/meta-arguments/count), create a single blob container resource definition that provisions three containers, naming them _prefix-[count#]_ -**Challenge:** Using your existing Terraform manifests, create a(nother) blob container, but rather than using the _count_ operator: +1. Using your existing Terraform manifests, create a(nother) blob container rather than using the _count_ operator: + +Hint: - Create a variable called `containersuffixlist` of type _list_ and have it contain the values `a`, `b`, and `c` - Use the [for_each](https://developer.hashicorp.com/terraform/language/meta-arguments/for_each) operator in conjunction with a second blob container resource definition to create three more containers with the names _prefix_-a, _prefix_-b, and _prefix_-c. ## Success Criteria -1. Use the Azure portal or Azure cli to verify new containers were added to the storage account. +1. Use the Azure portal or Azure CLI to verify that the new containers were added to the storage account. From e0ab00e9c4f5e53695328808dcd4bf28e2170b56 Mon Sep 17 00:00:00 2001 From: Pete Rodriguez Date: Fri, 12 May 2023 14:15:01 -0500 Subject: [PATCH 13/35] Update Terraform-Challenge-03.md --- 012-InfraAsCode-Terraform/Student/Terraform-Challenge-03.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/012-InfraAsCode-Terraform/Student/Terraform-Challenge-03.md b/012-InfraAsCode-Terraform/Student/Terraform-Challenge-03.md index 48c3852f93..d7f0f88441 100644 --- a/012-InfraAsCode-Terraform/Student/Terraform-Challenge-03.md +++ b/012-InfraAsCode-Terraform/Student/Terraform-Challenge-03.md @@ -1,6 +1,6 @@ # Challenge 3 - Advanced resource declarations -[< Previous Challenge](./Terraform-Challenge-02.md) - [Home](../README.md) - [Next Challenge >](./Terraform-Challenge-04.md) +[< Previous Challenge](./Challenge-02.md) - [Home](../README.md) - [Next Challenge >](./Challenge-04.md) ## Introduction From de0758e4cf82cbf6588e088623214351e391e5a4 Mon Sep 17 00:00:00 2001 From: Pete Rodriguez Date: Fri, 12 May 2023 14:16:39 -0500 Subject: [PATCH 14/35] Update Terraform-Challenge-04.md --- .../Student/Terraform-Challenge-04.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/012-InfraAsCode-Terraform/Student/Terraform-Challenge-04.md b/012-InfraAsCode-Terraform/Student/Terraform-Challenge-04.md index 7e6c9574ae..7047694b90 100644 --- a/012-InfraAsCode-Terraform/Student/Terraform-Challenge-04.md +++ b/012-InfraAsCode-Terraform/Student/Terraform-Challenge-04.md @@ -1,12 +1,12 @@ # Challenge 4 - Secret Values with Azure Key Vault -[< Previous Challenge](./Terraform-Challenge-03.md) - [Home](../README.md) - [Next Challenge >](./Terraform-Challenge-05.md) +[< Previous Challenge](./Challenge-03.md) - [Home](../README.md) - [Next Challenge >](./Challenge-05.md) ## Introduction The goals for this challenge are to understand how to handle secret values, e.g., **Don't encode secrets in your code!** -So far, the only parameters you have passed into your template have been related to storage accounts. In a later challenge, you will deploy resources requiring secret credentials as parameters. It is an **ANTI-pattern** to put a secret value such as a password in plain text in a parameter file! NEVER do this! +So far, the only parameters you have passed into your template have been related to storage accounts. In a later challenge, you will deploy resources requiring secret credentials as parameters. It is an **ANTI-pattern** to put a secret value such as a password in plain text in a parameter file! You should NEVER do this! It is a BEST practice to store secret values (such as passwords) in the Azure Key Vault service. @@ -14,10 +14,8 @@ It is a BEST practice to store secret values (such as passwords) in the Azure Ke In this challenge, you will create an Azure Key Vault and store a secret in it. Then you will create a Bicep template & parameters file that reads from the key vault. -## Challenges - + Create an Azure Key Vault using [azurerm_key_vault](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/key_vault) - + Note: Keyvaults require a unique name in Azure. Append your random suffix to the Keyvault name to ensure your name is unique. + + Note: Key vaults require a unique name in Azure. Append your random suffix to the Key vault name to ensure your name is unique. + Using the [azurerm_key_vault_key](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/key_vault_key) resource provider, create a key called `mysecret` with a [random password](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/password) and store it in the keyvault. + Explore the terraform state using the `terraform state list` and `terraform state show` commands to view the secret that was created + Discuss with your coach: What are the implications of the secret being stored in Terraform's state file? From 8df49998e6272a75ab3f502d8ddda54d8f807f54 Mon Sep 17 00:00:00 2001 From: Pete Rodriguez Date: Fri, 12 May 2023 14:20:30 -0500 Subject: [PATCH 15/35] Update Terraform-Challenge-04.md --- 012-InfraAsCode-Terraform/Student/Terraform-Challenge-04.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/012-InfraAsCode-Terraform/Student/Terraform-Challenge-04.md b/012-InfraAsCode-Terraform/Student/Terraform-Challenge-04.md index 7047694b90..af3a84cfd9 100644 --- a/012-InfraAsCode-Terraform/Student/Terraform-Challenge-04.md +++ b/012-InfraAsCode-Terraform/Student/Terraform-Challenge-04.md @@ -12,7 +12,7 @@ It is a BEST practice to store secret values (such as passwords) in the Azure Ke ## Description -In this challenge, you will create an Azure Key Vault and store a secret in it. Then you will create a Bicep template & parameters file that reads from the key vault. +In this challenge, you will create an Azure Key Vault and store a secret in it. Then you will create a Terraform template and tfvars file that reads from the key vault. + Create an Azure Key Vault using [azurerm_key_vault](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/key_vault) + Note: Key vaults require a unique name in Azure. Append your random suffix to the Key vault name to ensure your name is unique. From be836fad2c71ac7d819ae6eed0e590cee39f8b96 Mon Sep 17 00:00:00 2001 From: Pete Rodriguez Date: Fri, 12 May 2023 14:22:14 -0500 Subject: [PATCH 16/35] Update Terraform-Challenge-05.md --- .../Student/Terraform-Challenge-05.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/012-InfraAsCode-Terraform/Student/Terraform-Challenge-05.md b/012-InfraAsCode-Terraform/Student/Terraform-Challenge-05.md index 6e80360198..a4b487022a 100644 --- a/012-InfraAsCode-Terraform/Student/Terraform-Challenge-05.md +++ b/012-InfraAsCode-Terraform/Student/Terraform-Challenge-05.md @@ -1,6 +1,6 @@ # Challenge 5 - Deploy a Virtual Machine -[< Previous Challenge](./Terraform-Challenge-04.md) - [Home](../README.md) - [Next Challenge >](./Terraform-Challenge-06.md) +[< Previous Challenge](./Challenge-04.md) - [Home](../README.md) - [Next Challenge >](./Challenge-06.md) ## Introduction @@ -12,21 +12,21 @@ The goals for this challenge include understanding: + Clean code with neat parameter and variable values + Figuring out what Azure resources it takes to build a VM -## Challenge +## Description + Extend your Terraform to deploy a virtual machine: + VM requirements: + Linux OS - + Have terraform generate an SSH key and pass the public key to the VM. Store the private ssh key in the keyvault. + + Have terraform generate an SSH key and pass the public key to the VM. Store the private ssh key in the Azure Key Vault. + Extra credit: write your ssh private key to a local file + Use a resource prefix and template variables to have consistent naming of resources. ## Success Criteria 1. Verify that your virtual machine has been deployed via the Azure Portal or Azure CLI. -1. Connect to your virtual machine and verify you can login (Linux with SSH). (You will need to grab the ssh private key from the keyvault) +1. Connect to your virtual machine and verify you can login (Linux with SSH). (You will need to grab the ssh private key from the Key Vault) -## Tips +## Hints + It's up to you if you want to start with clean slate set of manifests or if you want to extend your current manifests to include a VM + Note that you will need to create a VNET, subnet, public IP, and NIC in addition to your VM. From 9d2712d0078176780f38f8d8d4bd79dd01da91db Mon Sep 17 00:00:00 2001 From: Pete Rodriguez Date: Fri, 12 May 2023 14:25:41 -0500 Subject: [PATCH 17/35] Update Terraform-Challenge-06.md --- .../Student/Terraform-Challenge-06.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/012-InfraAsCode-Terraform/Student/Terraform-Challenge-06.md b/012-InfraAsCode-Terraform/Student/Terraform-Challenge-06.md index 695121cfc9..f699b777c6 100644 --- a/012-InfraAsCode-Terraform/Student/Terraform-Challenge-06.md +++ b/012-InfraAsCode-Terraform/Student/Terraform-Challenge-06.md @@ -1,6 +1,6 @@ # Challenge 6 - Terraform Modules -[< Previous Challenge](./Terraform-Challenge-05.md) - [Home](../README.md) - [Next Challenge >](./Terraform-Challenge-07.md) +[< Previous Challenge](./Challenge-05.md) - [Home](../README.md) - [Next Challenge >](./Challenge-07.md) ## Introduction @@ -8,7 +8,7 @@ The goals for this challenge include understanding how Terraform modules allow f An application may require the composition of many underlying infrastructure resources in Azure. As you have now seen with just a single VM and its dependencies, a Terraform manifest can grow large rather quickly. -Terraform supports the concept of [*modules*](https://developer.hashicorp.com/terraform/language/modules). When you write a Bicep file you can call another Bicep file as a module. When your template is transpiled into JSON, a single ARM template is produced including the code from your module(s). +Terraform supports the concept of [*modules*](https://developer.hashicorp.com/terraform/language/modules). When you write a Terraform template you can call another Terraform file as a module. When templates get big, they become monoliths. They are hard to manage. By breaking your templates up into smaller modules, you can achieve more flexibility in how you manage your deployments. @@ -16,21 +16,21 @@ In many companies, deployment of cloud infrastructure may be managed by differen The network architecture and security groups are typically stable and do not change frequently. In contrast, application deployments that are deployed on the network may come and go. -## Challenge +## Description In this challenge you will separate your existing Terraform manifests deployment into modules -- Move the VM and its dependencies (VM, NIC, public-ip) into their own module. (eg move into a subdirectory). - - The module should take the following inputs: `resource group, location, vnname, admin username, ssh public key, subnet id` +- Move the VM and its dependencies (VM, NIC, public-ip) into their own module. (i.e., move into a subdirectory). + - The module should take the following inputs: `resource group, location, vmname, admin username, ssh public key, subnet id` - The module should output: `vm_public_ip_address` -- Move the vnet, subnet, and NSG definitions into their own module. The module should take the following parameters: +- Move the vnet, subnet, and NSG definitions into their own module. The module should take the following parameters: - `resource group, location, vnet name, address space, subnet name, subnet address prefix` By separating the networking resources into their own modules, an application team can test its infrastructure deployment in a test network. At a later point in time, the networking module can be replaced with a production module provided by the company's operations team. ## Success Criteria -1. Verify that all resources deploy as before when you had a single Bicep template. +1. Verify that all resources deploy as before when you had a single Terraform template. ## Learning Resources From 00829e2b7146dd38f5258d7f5e70ca1093577916 Mon Sep 17 00:00:00 2001 From: Pete Rodriguez Date: Fri, 12 May 2023 14:26:48 -0500 Subject: [PATCH 18/35] Update Terraform-Challenge-07.md --- 012-InfraAsCode-Terraform/Student/Terraform-Challenge-07.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/012-InfraAsCode-Terraform/Student/Terraform-Challenge-07.md b/012-InfraAsCode-Terraform/Student/Terraform-Challenge-07.md index 6817a27a8e..183ca57a8c 100644 --- a/012-InfraAsCode-Terraform/Student/Terraform-Challenge-07.md +++ b/012-InfraAsCode-Terraform/Student/Terraform-Challenge-07.md @@ -1,6 +1,6 @@ # Challenge 7 - Azure Container Apps (ACA) - Getting started -[< Previous Challenge](./Terraform-Challenge-06.md) - [Home](../README.md) - [Next Challenge>](./Terraform-Challenge-08.md) +[< Previous Challenge](./Challenge-06.md) - [Home](../README.md) - [Next Challenge>](./Challenge-08.md) ## Introduction @@ -13,7 +13,9 @@ Similar to Azure App Service, you will be deploying two components: It is recommended that you start fresh for this challenge and use a new set of Terraform resources (eg, new folder) & also use a new Terraform state file (eg, new key) -## Challenges +## Description + +In this challenge, you will accomplish the following tasks: + Deploy an [Azure Container Apps Environment](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/container_app_environment) using Terraform. - You will be required to deploy a Log Analytics Workspace to support this ACA Environment From d8db60b233ee7c6f0e0849c34951a28ac207b218 Mon Sep 17 00:00:00 2001 From: Pete Rodriguez Date: Fri, 12 May 2023 14:32:13 -0500 Subject: [PATCH 19/35] Update Terraform-Challenge-08.md --- .../Student/Terraform-Challenge-08.md | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/012-InfraAsCode-Terraform/Student/Terraform-Challenge-08.md b/012-InfraAsCode-Terraform/Student/Terraform-Challenge-08.md index 193be5a932..2d256d83ed 100644 --- a/012-InfraAsCode-Terraform/Student/Terraform-Challenge-08.md +++ b/012-InfraAsCode-Terraform/Student/Terraform-Challenge-08.md @@ -1,6 +1,6 @@ # Challenge 8 - Advanced Azure Container Apps (ACA) -[< Previous Challenge](./Terraform-Challenge-07.md) - [Home](../README.md) +[< Previous Challenge](./Challenge-07.md) - [Home](../README.md) ## Introduction In the prior challenge, we ran a very simple example of using ACA to host a hello-world app. @@ -9,17 +9,17 @@ In this challenge, we will expand on what we learned, and host a more complex th We will also explore the Terraform concept of "layered state files", where shared infrastructure components are deployed and managed separately from your application workloads -## Challenges +## Description -**Challenge Part 1**: In this first part of this challenge, we are going to deploy an Azure Container Registry (ACR) and and import some images to it. This ACR will be governed using a separate state file from the one we've been using for our other resources. This is a common pattern in Terraform, where you have shared infrastructure components that are deployed and managed separately from your application workloads. +**Part 1**: In this first part of this challenge, we are going to deploy an Azure Container Registry (ACR) and import some images to it. This ACR will be governed using a separate state file from the one we've been using for our other resources. This is a common pattern in Terraform, where you have shared infrastructure components that are deployed and managed separately from your application workloads. -First, create a new sub-folder within your working directory (eg, `acr`) and cd into it. This will be used to host the code for your ACR definition. +First, create a new sub-folder within your working directory (e.g., `acr`) and cd into it. This will be used to host the code for your ACR definition. Next, within this folder, create the appropriate Terraform manifest definitions to deploy an [Azure Container Registry (ACR)](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/container_registry). + Deploy this to a different state file! You can use the existing Storage Account and Blob Container, but use a (new) different key from your existing state file. This will allow you to manage the ACR separately from the rest of your resources. + Be sure to enable the Admin user on the ACR. You will need this for part 2. -We also need to import two container images into our ACR. There's no "official" way to do this using the standard terraform `azurerm` provider, so we are providing you a pre-authored module to use in your manifest. Add the following code to your manifest: +We also need to import two container images into our ACR. There's no "official" way to do this using the standard Terraform `azurerm` provider, so we are providing you a pre-authored module to use in your manifest. Add the following code to your manifest: ```hcl @@ -38,18 +38,18 @@ module "importimage" { ***Success Criteria***: Verify that the ACR is deployed and that the images are imported. You can do this by logging into the Azure Portal and navigating to the ACR resource. You should see the images listed under the Repositories section. -**Challenge Part 2**: Next, we will deploy a two-tier application to Azure Container Apps. This application will consist of a frontend web application, a backend API, and a SQL database. The application can be found in [this Github repo](https://github.com/microsoft/YADA). Specifically, there is already a script, available [here](https://github.com/microsoft/YADA/blob/main/deploy/ACA.md), that will deploy the application to Azure Container Apps. Your job is to take this example script and create a set of Terraform deployment manifests to deploy the application to your ACA environment. +**Part 2**: Next, we will deploy a two-tier application to Azure Container Apps. This application will consist of a frontend web application, a backend API, and a SQL database. The application can be found in [this Github repo](https://github.com/microsoft/YADA). Specifically, there is already a script, available [here](https://github.com/microsoft/YADA/blob/main/deploy/ACA.md), that will deploy the application to Azure Container Apps. Your job is to take this example script and create a set of Terraform deployment manifests to deploy the application to your ACA environment. ![Topology](https://github.com/microsoft/YADA/raw/main/web/app_arch.orig.png) Steps / Hints / Things to be aware of: -+ Be sure you are using a different Terraform state file than you used in Part 1. Eg, be sure you have cd'd out of the `acr` folder and are back in the root of your current working directory. ++ Be sure you are using a different Terraform state file than you used in Part 1. Be sure you have cd'd out of the `acr` folder and are back in the root of your current working directory. + Similar to the previous challenge (07), you'll need to create an [Azure Container Apps Environment](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/container_app_environment) using Terraform (and don't forget to deploy a Log Analytics Workspace to support this ACA Environment) + Deploy two [Azure Container Apps](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/container_app) from the container registry you created in the previous step. - - You will need to configure an ingress to be able to access the web app from the outside (eg, Internet) - - The api app should not be accessible from outside of the environment. - - You will need to appropriately set the environment variables for each app. Be sure to review the existing script to understand which variables need to be defined, abd be sure to review the hint below for the syntax of how to define environment variables in Terraform. Also review the readme page for each of the apps: + - You will need to configure an ingress to be able to access the web app from the Internet + - The API app should not be accessible from outside of the environment. + - You will need to appropriately set the environment variables for each app. Be sure to review the existing script to understand which variables need to be defined and be sure to review the hint below for the syntax of how to define environment variables in Terraform. Also, review the readme page for each of the apps: - [YADA Web](https://github.com/microsoft/YADA/blob/main/web/README.md) - [YADA API](https://github.com/microsoft/YADA/blob/main/api/README.md) - For your ACA app to be able to pull the images from your ACR, you will need to reference the ACR's adminuser & password in your container app definition. To do this, you will need to define the ACR as a Terraform `data` source. See [this example](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/container_registry) for more details. @@ -59,17 +59,17 @@ Steps / Hints / Things to be aware of: - Be sure to configure a set of firewall rules to allow access from the ACA Environment. _Hint: You'll need to reference the outbound ip address of your API app_ -Hint: To define environment variables within the ACA definition in Terraform, you can use the following syntax: _(The Terraform docs are not very clear on how to use multiple env variables, so we are providing this hint to help you out)_ +Hint: To define environment variables within the ACA definition in Terraform, you can use the following syntax: _(The Terraform docs are not very clear on how to use multiple env variables, so we are providing this hint to help you)_ ```hcl template { container { env { - name = "varable1" + name = "variable1" value = "value1" } env { - name = "varable2" + name = "variable2" value = "value2" } [...] @@ -84,7 +84,7 @@ Hint: To define environment variables within the ACA definition in Terraform, y - Healthcheck: OK - Shows the SQL version, eg `SQL Server version: Microsoft SQL Azure (RTM) - 12.0.2000.8 Mar 8 2023 17:58:50 Copyright (C) 2022 Microsoft Corporation` - Shows connectivity info for application tier -3. API tier is not accessable from the Internet. +3. API tier is not accessible from the Internet. Note that the links under `Direct Access to API` will not work. You would need to deploy an App Gateway to route those URIs properly. From c40e6cf45e6a55e8475cd36c2f2764758cda46f5 Mon Sep 17 00:00:00 2001 From: Pete Rodriguez Date: Fri, 12 May 2023 14:33:59 -0500 Subject: [PATCH 20/35] Rename Terraform-Challenge-00.md to Challenge-00.md --- .../Student/{Terraform-Challenge-00.md => Challenge-00.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename 012-InfraAsCode-Terraform/Student/{Terraform-Challenge-00.md => Challenge-00.md} (100%) diff --git a/012-InfraAsCode-Terraform/Student/Terraform-Challenge-00.md b/012-InfraAsCode-Terraform/Student/Challenge-00.md similarity index 100% rename from 012-InfraAsCode-Terraform/Student/Terraform-Challenge-00.md rename to 012-InfraAsCode-Terraform/Student/Challenge-00.md From 028b1641734f34c252b7bb02dff388905b415959 Mon Sep 17 00:00:00 2001 From: Pete Rodriguez Date: Fri, 12 May 2023 14:34:16 -0500 Subject: [PATCH 21/35] Rename Terraform-Challenge-01.md to Challenge-01.md --- .../Student/{Terraform-Challenge-01.md => Challenge-01.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename 012-InfraAsCode-Terraform/Student/{Terraform-Challenge-01.md => Challenge-01.md} (100%) diff --git a/012-InfraAsCode-Terraform/Student/Terraform-Challenge-01.md b/012-InfraAsCode-Terraform/Student/Challenge-01.md similarity index 100% rename from 012-InfraAsCode-Terraform/Student/Terraform-Challenge-01.md rename to 012-InfraAsCode-Terraform/Student/Challenge-01.md From 24d90f438732d148dc45799f386268e887000005 Mon Sep 17 00:00:00 2001 From: Pete Rodriguez Date: Fri, 12 May 2023 14:34:30 -0500 Subject: [PATCH 22/35] Rename Terraform-Challenge-02.md to Challenge-02.md --- .../Student/{Terraform-Challenge-02.md => Challenge-02.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename 012-InfraAsCode-Terraform/Student/{Terraform-Challenge-02.md => Challenge-02.md} (100%) diff --git a/012-InfraAsCode-Terraform/Student/Terraform-Challenge-02.md b/012-InfraAsCode-Terraform/Student/Challenge-02.md similarity index 100% rename from 012-InfraAsCode-Terraform/Student/Terraform-Challenge-02.md rename to 012-InfraAsCode-Terraform/Student/Challenge-02.md From 2522b3839623e06b23953af28f496f6a09e30302 Mon Sep 17 00:00:00 2001 From: Pete Rodriguez Date: Fri, 12 May 2023 14:34:44 -0500 Subject: [PATCH 23/35] Rename Terraform-Challenge-03.md to Challenge-03.md --- .../Student/{Terraform-Challenge-03.md => Challenge-03.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename 012-InfraAsCode-Terraform/Student/{Terraform-Challenge-03.md => Challenge-03.md} (100%) diff --git a/012-InfraAsCode-Terraform/Student/Terraform-Challenge-03.md b/012-InfraAsCode-Terraform/Student/Challenge-03.md similarity index 100% rename from 012-InfraAsCode-Terraform/Student/Terraform-Challenge-03.md rename to 012-InfraAsCode-Terraform/Student/Challenge-03.md From 37600c62c0e0194b671a4eabff50746e95b61c2f Mon Sep 17 00:00:00 2001 From: Pete Rodriguez Date: Fri, 12 May 2023 14:34:54 -0500 Subject: [PATCH 24/35] Rename Terraform-Challenge-04.md to Challenge-04.md --- .../Student/{Terraform-Challenge-04.md => Challenge-04.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename 012-InfraAsCode-Terraform/Student/{Terraform-Challenge-04.md => Challenge-04.md} (100%) diff --git a/012-InfraAsCode-Terraform/Student/Terraform-Challenge-04.md b/012-InfraAsCode-Terraform/Student/Challenge-04.md similarity index 100% rename from 012-InfraAsCode-Terraform/Student/Terraform-Challenge-04.md rename to 012-InfraAsCode-Terraform/Student/Challenge-04.md From 1214c7374f033feef5c102ee5d144adcb7211cb8 Mon Sep 17 00:00:00 2001 From: Pete Rodriguez Date: Fri, 12 May 2023 14:35:05 -0500 Subject: [PATCH 25/35] Rename Terraform-Challenge-05.md to Challenge-05.md --- .../Student/{Terraform-Challenge-05.md => Challenge-05.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename 012-InfraAsCode-Terraform/Student/{Terraform-Challenge-05.md => Challenge-05.md} (100%) diff --git a/012-InfraAsCode-Terraform/Student/Terraform-Challenge-05.md b/012-InfraAsCode-Terraform/Student/Challenge-05.md similarity index 100% rename from 012-InfraAsCode-Terraform/Student/Terraform-Challenge-05.md rename to 012-InfraAsCode-Terraform/Student/Challenge-05.md From 00e30cff2776f2354380adc8f57cc0a09472f443 Mon Sep 17 00:00:00 2001 From: Pete Rodriguez Date: Fri, 12 May 2023 14:35:15 -0500 Subject: [PATCH 26/35] Rename Terraform-Challenge-06.md to Challenge-06.md --- .../Student/{Terraform-Challenge-06.md => Challenge-06.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename 012-InfraAsCode-Terraform/Student/{Terraform-Challenge-06.md => Challenge-06.md} (100%) diff --git a/012-InfraAsCode-Terraform/Student/Terraform-Challenge-06.md b/012-InfraAsCode-Terraform/Student/Challenge-06.md similarity index 100% rename from 012-InfraAsCode-Terraform/Student/Terraform-Challenge-06.md rename to 012-InfraAsCode-Terraform/Student/Challenge-06.md From 830f290ad018c47cc33ac8c6a353a6042f7f86a7 Mon Sep 17 00:00:00 2001 From: Pete Rodriguez Date: Fri, 12 May 2023 14:35:28 -0500 Subject: [PATCH 27/35] Rename Terraform-Challenge-07.md to Challenge-07.md --- .../Student/{Terraform-Challenge-07.md => Challenge-07.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename 012-InfraAsCode-Terraform/Student/{Terraform-Challenge-07.md => Challenge-07.md} (100%) diff --git a/012-InfraAsCode-Terraform/Student/Terraform-Challenge-07.md b/012-InfraAsCode-Terraform/Student/Challenge-07.md similarity index 100% rename from 012-InfraAsCode-Terraform/Student/Terraform-Challenge-07.md rename to 012-InfraAsCode-Terraform/Student/Challenge-07.md From 83578234fd2bd7222841be609192e7851a093dd7 Mon Sep 17 00:00:00 2001 From: Pete Rodriguez Date: Fri, 12 May 2023 14:35:39 -0500 Subject: [PATCH 28/35] Rename Terraform-Challenge-08.md to Challenge-08.md --- .../Student/{Terraform-Challenge-08.md => Challenge-08.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename 012-InfraAsCode-Terraform/Student/{Terraform-Challenge-08.md => Challenge-08.md} (100%) diff --git a/012-InfraAsCode-Terraform/Student/Terraform-Challenge-08.md b/012-InfraAsCode-Terraform/Student/Challenge-08.md similarity index 100% rename from 012-InfraAsCode-Terraform/Student/Terraform-Challenge-08.md rename to 012-InfraAsCode-Terraform/Student/Challenge-08.md From d4b1b1c18985db0ee4651268b46a59e4c5825804 Mon Sep 17 00:00:00 2001 From: Pete Rodriguez Date: Fri, 12 May 2023 14:42:32 -0500 Subject: [PATCH 29/35] Update Challenge-03.md --- 012-InfraAsCode-Terraform/Student/Challenge-03.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/012-InfraAsCode-Terraform/Student/Challenge-03.md b/012-InfraAsCode-Terraform/Student/Challenge-03.md index d7f0f88441..c5016bb529 100644 --- a/012-InfraAsCode-Terraform/Student/Challenge-03.md +++ b/012-InfraAsCode-Terraform/Student/Challenge-03.md @@ -6,7 +6,7 @@ The goals for this challenge include understanding: -- How to create a set of resources based on a list or count (loops), eg iteration +- How to create a set of resources based on a list or count using an Terraform iteration meta-argument ## Description @@ -21,7 +21,7 @@ In this challenge, you will accomplish the following tasks: Hint: - Create a variable called `containersuffixlist` of type _list_ and have it contain the values `a`, `b`, and `c` -- Use the [for_each](https://developer.hashicorp.com/terraform/language/meta-arguments/for_each) operator in conjunction with a second blob container resource definition to create three more containers with the names _prefix_-a, _prefix_-b, and _prefix_-c. +- Use the [for_each](https://developer.hashicorp.com/terraform/language/meta-arguments/for_each) meta-argument in conjunction with a second blob container resource definition to create three more containers with the names _prefix_-a, _prefix_-b, and _prefix_-c. ## Success Criteria From ac0ecf1b1004797b2936d76b89266108d05e936c Mon Sep 17 00:00:00 2001 From: Pete Rodriguez Date: Fri, 12 May 2023 14:43:34 -0500 Subject: [PATCH 30/35] Update Challenge-04.md --- 012-InfraAsCode-Terraform/Student/Challenge-04.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/012-InfraAsCode-Terraform/Student/Challenge-04.md b/012-InfraAsCode-Terraform/Student/Challenge-04.md index af3a84cfd9..38a58ac97f 100644 --- a/012-InfraAsCode-Terraform/Student/Challenge-04.md +++ b/012-InfraAsCode-Terraform/Student/Challenge-04.md @@ -4,11 +4,11 @@ ## Introduction -The goals for this challenge are to understand how to handle secret values, e.g., **Don't encode secrets in your code!** +The goals for this challenge are to understand how to handle secret values. **Don't encode secrets in your code!** So far, the only parameters you have passed into your template have been related to storage accounts. In a later challenge, you will deploy resources requiring secret credentials as parameters. It is an **ANTI-pattern** to put a secret value such as a password in plain text in a parameter file! You should NEVER do this! -It is a BEST practice to store secret values (such as passwords) in the Azure Key Vault service. +It is a BEST practice to store secret values such as passwords in the Azure Key Vault service. ## Description From 9c5ead4a96e74d058c29620304d391c596be9dd3 Mon Sep 17 00:00:00 2001 From: Pete Rodriguez Date: Fri, 12 May 2023 14:44:27 -0500 Subject: [PATCH 31/35] Update Challenge-03.md --- 012-InfraAsCode-Terraform/Student/Challenge-03.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/012-InfraAsCode-Terraform/Student/Challenge-03.md b/012-InfraAsCode-Terraform/Student/Challenge-03.md index c5016bb529..4713ee7491 100644 --- a/012-InfraAsCode-Terraform/Student/Challenge-03.md +++ b/012-InfraAsCode-Terraform/Student/Challenge-03.md @@ -6,7 +6,7 @@ The goals for this challenge include understanding: -- How to create a set of resources based on a list or count using an Terraform iteration meta-argument +- How to create a set of resources based on a list or count using a Terraform iteration meta-argument ## Description From 4c46b5e49f691795e80c3c030fe131d56eb498ac Mon Sep 17 00:00:00 2001 From: Pete Rodriguez Date: Fri, 12 May 2023 14:45:09 -0500 Subject: [PATCH 32/35] Update Challenge-04.md --- 012-InfraAsCode-Terraform/Student/Challenge-04.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/012-InfraAsCode-Terraform/Student/Challenge-04.md b/012-InfraAsCode-Terraform/Student/Challenge-04.md index 38a58ac97f..51b570b8c8 100644 --- a/012-InfraAsCode-Terraform/Student/Challenge-04.md +++ b/012-InfraAsCode-Terraform/Student/Challenge-04.md @@ -22,8 +22,8 @@ In this challenge, you will create an Azure Key Vault and store a secret in it. ## Success Criteria -* Keyvault created -* Secret stored in the keyvault +* Azure Key Vault is created +* Secret stored in the Key Vault ## Suggested reading: From d4f4c6235f1e5dba7c2da4bf2ec2d8db86112ad1 Mon Sep 17 00:00:00 2001 From: Pete Rodriguez Date: Fri, 12 May 2023 14:47:00 -0500 Subject: [PATCH 33/35] Update Challenge-05.md --- .../Student/Challenge-05.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/012-InfraAsCode-Terraform/Student/Challenge-05.md b/012-InfraAsCode-Terraform/Student/Challenge-05.md index a4b487022a..b1ef1ff5b3 100644 --- a/012-InfraAsCode-Terraform/Student/Challenge-05.md +++ b/012-InfraAsCode-Terraform/Student/Challenge-05.md @@ -10,28 +10,28 @@ The goals for this challenge include understanding: + Globally unique naming context and complex dependencies + Clean code with neat parameter and variable values -+ Figuring out what Azure resources it takes to build a VM ++ What Azure resources it takes to build a VM ## Description + Extend your Terraform to deploy a virtual machine: + VM requirements: + Linux OS - + Have terraform generate an SSH key and pass the public key to the VM. Store the private ssh key in the Azure Key Vault. - + Extra credit: write your ssh private key to a local file + + Have Terraform generate an SSH key and pass the public key to the VM. Store the private SSH key in the Azure Key Vault. + + Extra credit: write your SSH private key to a local file + Use a resource prefix and template variables to have consistent naming of resources. ## Success Criteria 1. Verify that your virtual machine has been deployed via the Azure Portal or Azure CLI. -1. Connect to your virtual machine and verify you can login (Linux with SSH). (You will need to grab the ssh private key from the Key Vault) +1. Connect to your virtual machine and verify you can login (Linux with SSH). (You will need to grab the SSH private key from the Key Vault) ## Hints -+ It's up to you if you want to start with clean slate set of manifests or if you want to extend your current manifests to include a VM -+ Note that you will need to create a VNET, subnet, public IP, and NIC in addition to your VM. -+ You will need to open port 22 in your NSG to be able to ssh to the VM -+ You will need to supply your VM with a Public IP address or use the Azure Bastion service to connect to it. ++ It's up to you if you want to start with a clean slate set of manifests or if you want to extend your current manifests to include a VM ++ Note that you will need to create a VNET, subnet, public IP, and NIC in addition to your VM ++ You will need to open port 22 in your NSG to be able to SSH to the VM ++ You will need to supply your VM with a Public IP address or use the Azure Bastion service to connect to it ## Learning Resources From 657de06729ad758bf23e882e157bfd6de568bddd Mon Sep 17 00:00:00 2001 From: Pete Rodriguez Date: Fri, 12 May 2023 14:49:23 -0500 Subject: [PATCH 34/35] Update Challenge-07.md --- 012-InfraAsCode-Terraform/Student/Challenge-07.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/012-InfraAsCode-Terraform/Student/Challenge-07.md b/012-InfraAsCode-Terraform/Student/Challenge-07.md index 183ca57a8c..7806a32852 100644 --- a/012-InfraAsCode-Terraform/Student/Challenge-07.md +++ b/012-InfraAsCode-Terraform/Student/Challenge-07.md @@ -11,7 +11,7 @@ Similar to Azure App Service, you will be deploying two components: - A *Container Apps Environment*, which is the "plan" or "hosting" component of the service - An *Azure Container App*, which is the application itself -It is recommended that you start fresh for this challenge and use a new set of Terraform resources (eg, new folder) & also use a new Terraform state file (eg, new key) +It is recommended that you start fresh for this challenge and use a new set of Terraform resources (i.e., new folder) and also use a new Terraform state file (i.e., a new key) ## Description From 64ac4a20d9a82ca0c84144a5c7fa68d3bb616927 Mon Sep 17 00:00:00 2001 From: Pete Rodriguez Date: Fri, 12 May 2023 15:05:58 -0500 Subject: [PATCH 35/35] Update readme.md --- 012-InfraAsCode-Terraform/readme.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/012-InfraAsCode-Terraform/readme.md b/012-InfraAsCode-Terraform/readme.md index a3c56ff744..ea93eb7a7e 100644 --- a/012-InfraAsCode-Terraform/readme.md +++ b/012-InfraAsCode-Terraform/readme.md @@ -26,24 +26,24 @@ The challenges build upon each other incrementally. You will start by creating b ### Challenges -- Challenge 0: **[Pre-Requisites - Ready, Set, Go!](./Student/Terraform-Challenge-00.md)** - - Prepare your workstation to work with Azure & Terraform -- Challenge 1: **[Basic Terraform](./Student/Terraform-Challenge-01.md)** - - Develop a simple Terraform manifest that takes inputs to create an Azure Storage Account, and returns outputs -- Challenge 2: **[Terraform expressions and referencing resources](./Student/Terraform-Challenge-02.md)** +- Challenge 0: **[Pre-Requisites - Ready, Set, Go!](./Student/Challenge-00.md)** + - Prepare your workstation to work with Azure and Terraform +- Challenge 1: **[Basic Terraform](./Student/Challenge-01.md)** + - Develop a simple Terraform manifest that takes inputs to create an Azure Storage Account and returns outputs +- Challenge 2: **[Terraform expressions and referencing resources](./Student/Challenge-02.md)** - Learn Terraform expressions, conditionals, and referencing resources -- Challenge 3: **[Advanced resource declarations](./Student/Terraform-Challenge-03.md)** +- Challenge 3: **[Advanced resource declarations](./Student/Challenge-03.md)** - Advanced resource declarations including iteration -- Challenge 4: **[Secret Values with Azure Key Vault](./Student/Terraform-Challenge-04.md)** +- Challenge 4: **[Secret Values with Azure Key Vault](./Student/Challenge-04.md)** - Create and reference an Azure Key Vault -- Challenge 5: **[Deploy a Virtual Machine](./Student/Terraform-Challenge-05.md)** +- Challenge 5: **[Deploy a Virtual Machine](./Student/Challenge-05.md)** - Create a complex deployment with multiple dependencies -- Challenge 6: **[Terraform Modules](./Student/Terraform-Challenge-06.md)** +- Challenge 6: **[Terraform Modules](./Student/Challenge-06.md)** - Learn how create reusable modules for granular resource management - - Challenge 7: **[Azure Container Apps (ACA)](./Student/Terraform-Challenge-07.md)** + - Challenge 7: **[Azure Container Apps (ACA)](./Student/Challenge-07.md)** - Create an ACA environment and deploy a simple `hello world` application to it - - Challenge 8: **[Advanced ACA](./Student/Terraform-Challenge-08.md)** - - Provision an Azure container registry, import images to it, then provision and deploy a multi-microservice (frontend and backend) containerized application + - Challenge 8: **[Advanced ACA](./Student/Challenge-08.md)** + - Provision an Azure Container Registry, import images to it, then provision and deploy a multi-microservice (frontend and backend) containerized application