├── 09-A-Web-Server
├── modules
│ └── tls
│ │ ├── variables.tf
│ │ ├── main.tf
│ │ ├── README
│ │ ├── outputs.tf
│ │ └── LICENSE
├── outputs.tf
├── variables.tf
├── install_libraries.sh
├── main.tf
└── guide.md
├── .vscode
└── settings.json
├── 08-Modules
├── modules
│ └── tls
│ │ ├── README.md
│ │ ├── main.tf
│ │ ├── outputs.tf
│ │ ├── variables.tf
│ │ └── LICENSE
├── outputs.tf
├── variables.tf
├── main.tf
└── guide.md
├── 04-Variables-Continued
├── terraform.tfvars
├── main.tf
├── variables.tf
├── guide.md
└── .terraform.lock.hcl
├── 06-Data-Blocks
├── output.tf
├── variables.tf
├── main.tf
└── guide.md
├── 07-Another-Provider
├── output.tf
├── variables.tf
├── main.tf
├── guide.md
└── .terraform.lock.hcl
├── README.md
├── 05-AWS-Setup-and-Outputs
├── variables.tf
├── main.tf
├── .terraform.lock.hcl
└── guide.md
├── 02-Lock-and-State-Files
├── main.tf
├── .terraform.lock.hcl
└── guide.md
├── .devcontainer
├── Dockerfile
└── devcontainer.json
├── .gitignore
├── 03-Variables
├── main.tf
├── guide.md
└── .terraform.lock.hcl
├── LICENSE
└── 01-Basic-Commands
├── .terraform.lock.hcl
├── main.tf
└── guide.md
/09-A-Web-Server/modules/tls/variables.tf:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "cSpell.words": [
3 | "kreuzwerker"
4 | ]
5 | }
--------------------------------------------------------------------------------
/09-A-Web-Server/modules/tls/main.tf:
--------------------------------------------------------------------------------
1 | resource "tls_private_key" "mykey" {
2 | algorithm = "RSA"
3 | rsa_bits = 4096
4 | }
--------------------------------------------------------------------------------
/08-Modules/modules/tls/README.md:
--------------------------------------------------------------------------------
1 | # TLS Module
2 |
3 | Creates a private/public key pair to be used with EC2 instances to ssh into them.
--------------------------------------------------------------------------------
/08-Modules/modules/tls/main.tf:
--------------------------------------------------------------------------------
1 | resource "tls_private_key" "mykey" {
2 | algorithm = var.algorithm
3 | rsa_bits = var.rsa_bits
4 | }
--------------------------------------------------------------------------------
/09-A-Web-Server/modules/tls/README:
--------------------------------------------------------------------------------
1 | # TLS Module
2 |
3 | Creates a private/public key pair to be used with EC2 instances to ssh into them.
--------------------------------------------------------------------------------
/04-Variables-Continued/terraform.tfvars:
--------------------------------------------------------------------------------
1 | image_name = "nginx"
2 | image_tag = "1.23.3"
3 | internal_port = 80
4 | external_port = 8090
--------------------------------------------------------------------------------
/06-Data-Blocks/output.tf:
--------------------------------------------------------------------------------
1 | output "public_ip" {
2 | value = aws_instance.webserver.public_ip
3 | description = "EC2 Public IP"
4 | }
--------------------------------------------------------------------------------
/09-A-Web-Server/outputs.tf:
--------------------------------------------------------------------------------
1 | output "public_ip" {
2 | value = aws_instance.webserver.public_ip
3 | description = "EC2 Public IP"
4 | }
--------------------------------------------------------------------------------
/08-Modules/outputs.tf:
--------------------------------------------------------------------------------
1 | output "public_ip" {
2 | value = aws_instance.webserver.public_ip
3 | description = "EC2 Public IP"
4 | }
5 |
6 | output "private_key" {
7 | value = module.tls.private_key_out
8 | sensitive = true
9 | }
--------------------------------------------------------------------------------
/08-Modules/modules/tls/outputs.tf:
--------------------------------------------------------------------------------
1 | output "private_key_out" {
2 | value = tls_private_key.mykey.private_key_pem
3 | sensitive = true
4 | }
5 |
6 | output "public_key_out" {
7 | value = tls_private_key.mykey.public_key_openssh
8 | }
9 |
--------------------------------------------------------------------------------
/09-A-Web-Server/modules/tls/outputs.tf:
--------------------------------------------------------------------------------
1 | output "private_key" {
2 | value = tls_private_key.mykey.private_key_pem
3 | sensitive = true
4 | }
5 |
6 | output "public_key_out" {
7 | value = tls_private_key.mykey.public_key_openssh
8 | }
9 |
--------------------------------------------------------------------------------
/08-Modules/modules/tls/variables.tf:
--------------------------------------------------------------------------------
1 | variable "algorithm" {
2 | type = string
3 | description = "The algorithm used"
4 | }
5 |
6 | variable "rsa_bits" {
7 | type = number
8 | description = "The strength of the algorithm in bits"
9 | }
--------------------------------------------------------------------------------
/07-Another-Provider/output.tf:
--------------------------------------------------------------------------------
1 | output "public_ip" {
2 | value = aws_instance.webserver.public_ip
3 | description = "EC2 Public IP"
4 | }
5 |
6 | output "private_key" {
7 | value = tls_private_key.mykey.private_key_pem
8 | sensitive = true
9 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Overview
2 | A repo to teach Terraform for beginners.
3 |
4 | You can watch the [accompanied video on YouTube.](https://www.youtube.com/watch?v=HbG3zVBVYvM) along with a [written tutorial on my blog post.](https://tekanaid.com/posts/terraform-for-beginners-course-and-training)
5 |
6 |
--------------------------------------------------------------------------------
/05-AWS-Setup-and-Outputs/variables.tf:
--------------------------------------------------------------------------------
1 | variable "region" {
2 | type = string
3 | description = "The AWS region"
4 | default = "us-east-1"
5 | }
6 |
7 | variable "my_instance_type" {
8 | type = string
9 | description = "EC2 instance type"
10 | default = "t2.micro"
11 | }
--------------------------------------------------------------------------------
/08-Modules/variables.tf:
--------------------------------------------------------------------------------
1 | variable "region" {
2 | type = string
3 | description = "The AWS region"
4 | default = "us-east-1"
5 | }
6 |
7 | variable "my_aws_key" {
8 | type = string
9 | description = "AWS key to SSH into EC2 instances"
10 | default = "mykey.pem"
11 | }
12 |
13 | variable "my_instance_type" {
14 | type = string
15 | description = "EC2 instance type"
16 | default = "t2.micro"
17 | }
--------------------------------------------------------------------------------
/06-Data-Blocks/variables.tf:
--------------------------------------------------------------------------------
1 | variable "region" {
2 | type = string
3 | description = "The AWS region"
4 | default = "us-east-1"
5 | }
6 |
7 | variable "my_aws_key" {
8 | type = string
9 | description = "AWS key to SSH into EC2 instances"
10 | default = "mykey.pem"
11 | }
12 |
13 | variable "my_instance_type" {
14 | type = string
15 | description = "EC2 instance type"
16 | default = "t2.micro"
17 | }
--------------------------------------------------------------------------------
/09-A-Web-Server/variables.tf:
--------------------------------------------------------------------------------
1 | variable "region" {
2 | type = string
3 | description = "The AWS region"
4 | default = "us-east-1"
5 | }
6 |
7 | variable "my_aws_key" {
8 | type = string
9 | description = "AWS key to SSH into EC2 instances"
10 | default = "mykey.pem"
11 | }
12 |
13 | variable "my_instance_type" {
14 | type = string
15 | description = "EC2 instance type"
16 | default = "t2.micro"
17 | }
--------------------------------------------------------------------------------
/07-Another-Provider/variables.tf:
--------------------------------------------------------------------------------
1 | variable "region" {
2 | type = string
3 | description = "The AWS region"
4 | default = "us-east-1"
5 | }
6 |
7 | variable "my_aws_key" {
8 | type = string
9 | description = "AWS key to SSH into EC2 instances"
10 | default = "mykey.pem"
11 | }
12 |
13 | variable "my_instance_type" {
14 | type = string
15 | description = "EC2 instance type"
16 | default = "t2.micro"
17 | }
--------------------------------------------------------------------------------
/05-AWS-Setup-and-Outputs/main.tf:
--------------------------------------------------------------------------------
1 | terraform {
2 | required_providers {
3 | aws = {
4 | source = "hashicorp/aws"
5 | version = "4.19.0"
6 | }
7 | }
8 | }
9 |
10 | provider "aws" {
11 | region = var.region
12 | }
13 |
14 | resource "aws_instance" "webserver" {
15 | ami = "ami-08d4ac5b634553e16"
16 | instance_type = var.my_instance_type
17 | }
18 |
19 | output "public_ip" {
20 | value = aws_instance.webserver.public_ip
21 | description = "EC2 Public IP"
22 | }
23 |
--------------------------------------------------------------------------------
/02-Lock-and-State-Files/main.tf:
--------------------------------------------------------------------------------
1 | terraform {
2 | required_providers {
3 | docker = {
4 | source = "kreuzwerker/docker"
5 | version = "3.0.1"
6 | }
7 | }
8 | }
9 |
10 | provider "docker" {}
11 |
12 | resource "docker_image" "nginx_image" {
13 | name = "nginx:1.23.3"
14 | }
15 |
16 | resource "docker_container" "nginx_container" {
17 | name = "web-server"
18 | image = docker_image.nginx_image.image_id
19 | ports {
20 | internal = 80
21 | external = 8080
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/.devcontainer/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM mcr.microsoft.com/devcontainers/universal:2-linux
2 | ARG TERRAFORM_VERSION=1.3.7
3 | USER root
4 | # Install Terraform and VAULT
5 | RUN wget https://releases.hashicorp.com/terraform/${TERRAFORM_VERSION}/terraform_${TERRAFORM_VERSION}_linux_amd64.zip && \
6 | unzip terraform_${TERRAFORM_VERSION}_linux_amd64.zip && \
7 | mv terraform /usr/bin && \
8 | rm terraform_${TERRAFORM_VERSION}_linux_amd64.zip && \
9 | # Install AWS
10 | pip install --upgrade pip && \
11 | pip install --upgrade awscli
12 | USER codespace
13 |
--------------------------------------------------------------------------------
/04-Variables-Continued/main.tf:
--------------------------------------------------------------------------------
1 | terraform {
2 | required_providers {
3 | docker = {
4 | source = "kreuzwerker/docker"
5 | version = "3.0.1"
6 | }
7 | }
8 | }
9 |
10 | provider "docker" {}
11 |
12 | resource "docker_image" "nginx_image" {
13 | name = "${var.image_name}:${var.image_tag}"
14 | }
15 |
16 | resource "docker_container" "nginx_container" {
17 | name = "web-server"
18 | image = docker_image.nginx_image.image_id
19 | ports {
20 | internal = var.internal_port
21 | external = var.external_port
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/04-Variables-Continued/variables.tf:
--------------------------------------------------------------------------------
1 | variable "image_name" {
2 | type = string
3 | description = "The name of the Docker image"
4 | }
5 |
6 | variable "image_tag" {
7 | type = string
8 | description = "The tag of the Docker image"
9 | }
10 |
11 | variable "internal_port" {
12 | type = number
13 | description = "The internal port number for the container"
14 | default = 80
15 | }
16 |
17 | variable "external_port" {
18 | type = number
19 | description = "The external port number for the container"
20 | default = 8080
21 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Local .terraform directories
2 | **/.terraform/*
3 |
4 | # .tfstate files
5 | *.tfstate
6 | *.tfstate.*
7 |
8 | # Crash log files
9 | crash.log
10 |
11 | # Ignore any .tfvars files that are generated automatically for each Terraform run. Most
12 | # .tfvars files are managed as part of configuration and so should be included in
13 | # version control.
14 | #
15 | # example.tfvars
16 |
17 | # Ignore override files as they are usually used to override resources locally and so
18 | # are not checked in
19 | override.tf
20 | override.tf.json
21 | *_override.tf
22 | *_override.tf.json
23 |
24 | # Include override files you do wish to add to version control using negated pattern
25 | #
26 | # !example_override.tf
27 |
28 | # Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan
29 | # example: *tfplan*
30 | *.pem
31 |
--------------------------------------------------------------------------------
/06-Data-Blocks/main.tf:
--------------------------------------------------------------------------------
1 | terraform {
2 | required_providers {
3 | aws = {
4 | source = "hashicorp/aws"
5 | version = "4.19.0"
6 | }
7 | tls = {
8 | source = "hashicorp/tls"
9 | version = "4.0.0"
10 | }
11 | }
12 | }
13 |
14 | provider "aws" {
15 | region = var.region
16 | }
17 |
18 | data "aws_ami" "ubuntu" {
19 | most_recent = true
20 |
21 | filter {
22 | name = "name"
23 | values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"]
24 | }
25 |
26 | filter {
27 | name = "virtualization-type"
28 | values = ["hvm"]
29 | }
30 |
31 | owners = ["099720109477"] # Canonical https://ubuntu.com/server/docs/cloud-images/amazon-ec2
32 | }
33 |
34 | resource "aws_instance" "webserver" {
35 | ami = data.aws_ami.ubuntu.id
36 | instance_type = var.my_instance_type
37 | }
--------------------------------------------------------------------------------
/04-Variables-Continued/guide.md:
--------------------------------------------------------------------------------
1 | # Variables
2 |
3 | In this lab we learn about Variables.
4 |
5 | ## Instructions
6 |
7 | 1. Change directory into the `04-Variables-Continued` directory:
8 |
9 | ```bash
10 | cd 04-Variables-Continued
11 | ```
12 |
13 | 2. Initialize and Terraform Apply
14 |
15 | ```bash
16 | terraform init
17 | terraform apply --auto-approve
18 | ```
19 |
20 | 3. Examine the `variables.tf` file
21 |
22 | Notice that we just moved the 4 variable blocks here. Terraform doesn't care how many `.tf` files you have, it will merge all of these files that live in the same directory.
23 |
24 | This `variables.tf` file is used to declare our variables with reasonable defaults if applicable.
25 |
26 | 4. Examine the `terraform.tfvars` file
27 |
28 | This file is used to assign values to our variables and will override the default values assigned in the `variables.tf` file.
29 |
30 | 5. Now go ahead and destroy the environment.
31 |
32 | ```bash
33 | terraform destroy --auto-approve
34 | ```
35 |
36 | > Congratulations you have finished this lab!
37 |
38 |
--------------------------------------------------------------------------------
/03-Variables/main.tf:
--------------------------------------------------------------------------------
1 | terraform {
2 | required_providers {
3 | docker = {
4 | source = "kreuzwerker/docker"
5 | version = "3.0.1"
6 | }
7 | }
8 | }
9 |
10 | provider "docker" {}
11 |
12 | resource "docker_image" "nginx_image" {
13 | name = "${var.image_name}:${var.image_tag}"
14 | }
15 |
16 | resource "docker_container" "nginx_container" {
17 | name = "web-server"
18 | image = docker_image.nginx_image.image_id
19 | ports {
20 | internal = var.internal_port
21 | external = var.external_port
22 | }
23 | }
24 |
25 | variable "image_name" {
26 | type = string
27 | description = "The name of the Docker image"
28 | default = "nginx"
29 | }
30 |
31 | variable "image_tag" {
32 | type = string
33 | description = "The tag of the Docker image"
34 | default = "1.23.3"
35 | }
36 |
37 | variable "internal_port" {
38 | type = number
39 | description = "The internal port number for the container"
40 | }
41 |
42 | variable "external_port" {
43 | type = number
44 | description = "The external port number for the container"
45 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 Sam
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/08-Modules/modules/tls/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 TeKanAid Solutions Inc.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/09-A-Web-Server/modules/tls/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 TeKanAid Solutions Inc.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/09-A-Web-Server/install_libraries.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | echo "Installing tree, jq, and nginx"
3 | apt -y update
4 | apt install tree jq -y
5 | apt install nginx -y
6 | systemctl enable nginx
7 | sudo cat << EOF > /tmp/index.html
8 |
9 |
10 | Schoolapp
11 |
12 |
13 | Welcome to the School App
14 |
15 |
16 |
17 |
18 | Photo by AltumCode on Unsplash
19 |
20 | This message confirms that your App is working with an NGINX web server. Great work!
21 |
22 |
23 | EOF
24 | sudo mv /tmp/index.html /var/www/html/index.html
25 | sudo nginx -s reload
26 |
--------------------------------------------------------------------------------
/05-AWS-Setup-and-Outputs/.terraform.lock.hcl:
--------------------------------------------------------------------------------
1 | # This file is maintained automatically by "terraform init".
2 | # Manual edits may be lost in future updates.
3 |
4 | provider "registry.terraform.io/hashicorp/aws" {
5 | version = "4.19.0"
6 | constraints = "4.19.0"
7 | hashes = [
8 | "h1:4vAZv9/3q5z78CV+YAumfuaoSNSNwAXDEhI/XnGVM5E=",
9 | "zh:22820bfa0065f583298015367f8dc015dffa5b19b76dbd78ecf5da8d7d599573",
10 | "zh:31a5c5fade4bd30dbc2b15f448cebb9ed527793c607e8687d3b2101bcf2c4471",
11 | "zh:37c9e469e51aa835a5542510561397541de08b62fc15292588382932624fcf88",
12 | "zh:398bfe1ba7428ef03293c6618067ddd8c0aaae8bbe764177ae951259228af724",
13 | "zh:4610f5a93ef956103d719ae73872a52ecd6cb321452c26a879896348bc27eed9",
14 | "zh:4a0d570dc5f01f41538b4eb70086a00dfb25c5d00fd27c950ac209d3609486f6",
15 | "zh:4fb65ce84801f82a3beb4e2cb72c5d52ca04d4717ed3890b206da346f02d5def",
16 | "zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425",
17 | "zh:9bb3919bd6d94fb22025540f0c1db5eceec8927bd71b8fbdcd295609c999065f",
18 | "zh:ce2623a13f74677cdb948607e456ce00407c57333b8310d5c9d053fc3defbc78",
19 | "zh:e0d57e8784e6ccfa96fdd07ae1ddcc947be242bc11e7a5dd16b520b4204e0d09",
20 | "zh:f988b7c37e95a5b3a493a6b9dcc5ed270136f97d5c0effa84a51940f71626c12",
21 | ]
22 | }
23 |
--------------------------------------------------------------------------------
/05-AWS-Setup-and-Outputs/guide.md:
--------------------------------------------------------------------------------
1 | # AWS Setup and Outputs
2 |
3 | In this lab we learn about AWS with Terraform and Terraform Outputs.
4 |
5 | ## Instructions
6 |
7 | 1. Change directory into the `05-AWS-Setup-and-Outputs` directory:
8 |
9 | ```bash
10 | cd 05-AWS-Setup-and-Outputs
11 | ```
12 |
13 | 2. Create environment variables to connect to AWS
14 |
15 | ```bash
16 | export AWS_ACCESS_KEY_ID=your_value
17 | export AWS_SECRET_ACCESS_KEY=your_value
18 | ```
19 |
20 | 3. Initialize Terraform Plan, and Terraform Apply
21 |
22 | ```bash
23 | terraform init
24 | terraform plan
25 | terraform apply --auto-approve
26 | ```
27 |
28 | Notice the output of Terraform gives us the public IP of the EC2 instance.
29 |
30 | 4. Examine the `main.tf` file
31 |
32 | We are now using the `aws` provider. Also the `output` block is referencing the `public_ip` attribute of the EC2 instance likie this: `aws_instance.webserver.public_ip`
33 |
34 | 5. Examine the `variables.tf` file
35 |
36 | We have 2 variables defined with defaults:
37 | - region
38 | - my_instance_type
39 |
40 | 6. Check the EC2 instance that got created in the AWS console
41 |
42 | 7. Now go ahead and destroy the environment.
43 |
44 | ```bash
45 | terraform destroy --auto-approve
46 | ```
47 |
48 | > Congratulations you have finished this lab!
49 |
50 |
--------------------------------------------------------------------------------
/03-Variables/guide.md:
--------------------------------------------------------------------------------
1 | # Variables
2 |
3 | In this lab we learn about Variables.
4 |
5 | ## Instructions
6 |
7 | 1. Change directory into the `03-Variables` directory:
8 |
9 | ```bash
10 | cd 03-Variables
11 | ```
12 |
13 | 2. Initialize and Terraform Apply
14 |
15 | ```bash
16 | terraform init
17 | terraform apply --auto-approve
18 | ```
19 |
20 | You will get prompted for the External and Internal ports.
21 | Use 8080 for the external port and 80 for the internal port.
22 |
23 | 3. Examine the `main.tf` file
24 |
25 | Notice how we declare variables using the `variables` block and reference variables using var..
26 |
27 | This syntax: `"${var.image_name}:${var.image_tag}"` is called string interpolation as you can include variables inside strings.
28 |
29 | 4. Supply the variables via the CLI
30 |
31 | Now rerun `terraform apply` but this time use the following command:
32 |
33 | ```bash
34 | terraform apply -var 'external_port=8080' -var 'internal_port=80'
35 | ```
36 |
37 | 5. Now go ahead and destroy the environment using the `-destroy` flag which is another way of destroying the environment that is often used in CI/CD pipelines.
38 |
39 | ```bash
40 | terraform apply -destroy -var 'external_port=8080' -var 'internal_port=80'
41 | ```
42 |
43 | > Congratulations you have finished this lab!
44 |
45 |
--------------------------------------------------------------------------------
/03-Variables/.terraform.lock.hcl:
--------------------------------------------------------------------------------
1 | # This file is maintained automatically by "terraform init".
2 | # Manual edits may be lost in future updates.
3 |
4 | provider "registry.terraform.io/kreuzwerker/docker" {
5 | version = "3.0.1"
6 | constraints = "3.0.1"
7 | hashes = [
8 | "h1:X2wZHQoG54NmtojeFcX0PSJPelaIejQRqyyI2h+LjWg=",
9 | "zh:02f60126ca16b344092df3c315296bf1a216c3b2a68eddb3c89fdfa5ea826118",
10 | "zh:0d2ee9624a54dbc10538b0c4e296348641b9bfba1354b3f872e43f7ec69a75f2",
11 | "zh:473d7427da8c9efc231266abc7fdc27fca5f9ee0bdfcdb9914f0a2886e3e23b8",
12 | "zh:5f0189bcd0c944c001098cb17a23efa79df8f0eec8644a64fe0e4200983ba5b7",
13 | "zh:6200319c41d6baad3f46701a4028412f8ae2496e29fc4fef9584cc71da5fbbe6",
14 | "zh:650be621f2216b1240f148eae8fcf80ec57c35925e2b212db7c23a70b9e67e06",
15 | "zh:72fcfa6207251105066a34f0ec6d27ecc658b565e84fa946da376dd1afadd265",
16 | "zh:92fc352a2090d3d380c7c8e8bbdf6f99d93a0182701056bb1d2dbfd5049e8ca6",
17 | "zh:a7e2ef666c2a7eb5661b06cfbd7635cb9543524e7bf6a3851dcf6eacc9950cc4",
18 | "zh:a8604595e61e8919c51a8656800c8c64557f9a2bc00309315895b380f2e9be19",
19 | "zh:caf65603a84b749d8f3af2ee47b66f7e21d481f981e2e1d1d59838751c5e3be4",
20 | "zh:dad40c4e57da284e7f57b5c0cc9dfac3cb27b01d2f2436fbe3464f0a2111b262",
21 | "zh:dc1b173dbcba9d74879b16f36f6d9e97ef62fbd6fca8db79ec4fe4ec69c0e2f3",
22 | "zh:e506d04677383b6d62bd69d42dc9005e27a45ccc2efc6e0de607e1f8445981d2",
23 | ]
24 | }
25 |
--------------------------------------------------------------------------------
/01-Basic-Commands/.terraform.lock.hcl:
--------------------------------------------------------------------------------
1 | # This file is maintained automatically by "terraform init".
2 | # Manual edits may be lost in future updates.
3 |
4 | provider "registry.terraform.io/kreuzwerker/docker" {
5 | version = "3.0.1"
6 | constraints = "3.0.1"
7 | hashes = [
8 | "h1:X2wZHQoG54NmtojeFcX0PSJPelaIejQRqyyI2h+LjWg=",
9 | "zh:02f60126ca16b344092df3c315296bf1a216c3b2a68eddb3c89fdfa5ea826118",
10 | "zh:0d2ee9624a54dbc10538b0c4e296348641b9bfba1354b3f872e43f7ec69a75f2",
11 | "zh:473d7427da8c9efc231266abc7fdc27fca5f9ee0bdfcdb9914f0a2886e3e23b8",
12 | "zh:5f0189bcd0c944c001098cb17a23efa79df8f0eec8644a64fe0e4200983ba5b7",
13 | "zh:6200319c41d6baad3f46701a4028412f8ae2496e29fc4fef9584cc71da5fbbe6",
14 | "zh:650be621f2216b1240f148eae8fcf80ec57c35925e2b212db7c23a70b9e67e06",
15 | "zh:72fcfa6207251105066a34f0ec6d27ecc658b565e84fa946da376dd1afadd265",
16 | "zh:92fc352a2090d3d380c7c8e8bbdf6f99d93a0182701056bb1d2dbfd5049e8ca6",
17 | "zh:a7e2ef666c2a7eb5661b06cfbd7635cb9543524e7bf6a3851dcf6eacc9950cc4",
18 | "zh:a8604595e61e8919c51a8656800c8c64557f9a2bc00309315895b380f2e9be19",
19 | "zh:caf65603a84b749d8f3af2ee47b66f7e21d481f981e2e1d1d59838751c5e3be4",
20 | "zh:dad40c4e57da284e7f57b5c0cc9dfac3cb27b01d2f2436fbe3464f0a2111b262",
21 | "zh:dc1b173dbcba9d74879b16f36f6d9e97ef62fbd6fca8db79ec4fe4ec69c0e2f3",
22 | "zh:e506d04677383b6d62bd69d42dc9005e27a45ccc2efc6e0de607e1f8445981d2",
23 | ]
24 | }
25 |
--------------------------------------------------------------------------------
/02-Lock-and-State-Files/.terraform.lock.hcl:
--------------------------------------------------------------------------------
1 | # This file is maintained automatically by "terraform init".
2 | # Manual edits may be lost in future updates.
3 |
4 | provider "registry.terraform.io/kreuzwerker/docker" {
5 | version = "3.0.1"
6 | constraints = "3.0.1"
7 | hashes = [
8 | "h1:X2wZHQoG54NmtojeFcX0PSJPelaIejQRqyyI2h+LjWg=",
9 | "zh:02f60126ca16b344092df3c315296bf1a216c3b2a68eddb3c89fdfa5ea826118",
10 | "zh:0d2ee9624a54dbc10538b0c4e296348641b9bfba1354b3f872e43f7ec69a75f2",
11 | "zh:473d7427da8c9efc231266abc7fdc27fca5f9ee0bdfcdb9914f0a2886e3e23b8",
12 | "zh:5f0189bcd0c944c001098cb17a23efa79df8f0eec8644a64fe0e4200983ba5b7",
13 | "zh:6200319c41d6baad3f46701a4028412f8ae2496e29fc4fef9584cc71da5fbbe6",
14 | "zh:650be621f2216b1240f148eae8fcf80ec57c35925e2b212db7c23a70b9e67e06",
15 | "zh:72fcfa6207251105066a34f0ec6d27ecc658b565e84fa946da376dd1afadd265",
16 | "zh:92fc352a2090d3d380c7c8e8bbdf6f99d93a0182701056bb1d2dbfd5049e8ca6",
17 | "zh:a7e2ef666c2a7eb5661b06cfbd7635cb9543524e7bf6a3851dcf6eacc9950cc4",
18 | "zh:a8604595e61e8919c51a8656800c8c64557f9a2bc00309315895b380f2e9be19",
19 | "zh:caf65603a84b749d8f3af2ee47b66f7e21d481f981e2e1d1d59838751c5e3be4",
20 | "zh:dad40c4e57da284e7f57b5c0cc9dfac3cb27b01d2f2436fbe3464f0a2111b262",
21 | "zh:dc1b173dbcba9d74879b16f36f6d9e97ef62fbd6fca8db79ec4fe4ec69c0e2f3",
22 | "zh:e506d04677383b6d62bd69d42dc9005e27a45ccc2efc6e0de607e1f8445981d2",
23 | ]
24 | }
25 |
--------------------------------------------------------------------------------
/04-Variables-Continued/.terraform.lock.hcl:
--------------------------------------------------------------------------------
1 | # This file is maintained automatically by "terraform init".
2 | # Manual edits may be lost in future updates.
3 |
4 | provider "registry.terraform.io/kreuzwerker/docker" {
5 | version = "3.0.1"
6 | constraints = "3.0.1"
7 | hashes = [
8 | "h1:X2wZHQoG54NmtojeFcX0PSJPelaIejQRqyyI2h+LjWg=",
9 | "zh:02f60126ca16b344092df3c315296bf1a216c3b2a68eddb3c89fdfa5ea826118",
10 | "zh:0d2ee9624a54dbc10538b0c4e296348641b9bfba1354b3f872e43f7ec69a75f2",
11 | "zh:473d7427da8c9efc231266abc7fdc27fca5f9ee0bdfcdb9914f0a2886e3e23b8",
12 | "zh:5f0189bcd0c944c001098cb17a23efa79df8f0eec8644a64fe0e4200983ba5b7",
13 | "zh:6200319c41d6baad3f46701a4028412f8ae2496e29fc4fef9584cc71da5fbbe6",
14 | "zh:650be621f2216b1240f148eae8fcf80ec57c35925e2b212db7c23a70b9e67e06",
15 | "zh:72fcfa6207251105066a34f0ec6d27ecc658b565e84fa946da376dd1afadd265",
16 | "zh:92fc352a2090d3d380c7c8e8bbdf6f99d93a0182701056bb1d2dbfd5049e8ca6",
17 | "zh:a7e2ef666c2a7eb5661b06cfbd7635cb9543524e7bf6a3851dcf6eacc9950cc4",
18 | "zh:a8604595e61e8919c51a8656800c8c64557f9a2bc00309315895b380f2e9be19",
19 | "zh:caf65603a84b749d8f3af2ee47b66f7e21d481f981e2e1d1d59838751c5e3be4",
20 | "zh:dad40c4e57da284e7f57b5c0cc9dfac3cb27b01d2f2436fbe3464f0a2111b262",
21 | "zh:dc1b173dbcba9d74879b16f36f6d9e97ef62fbd6fca8db79ec4fe4ec69c0e2f3",
22 | "zh:e506d04677383b6d62bd69d42dc9005e27a45ccc2efc6e0de607e1f8445981d2",
23 | ]
24 | }
25 |
--------------------------------------------------------------------------------
/06-Data-Blocks/guide.md:
--------------------------------------------------------------------------------
1 | # Data Blocks
2 |
3 | In this lab we learn about Data Blocks.
4 |
5 | ## Instructions
6 |
7 | 1. Change directory into the `06-Data-Blocks` directory:
8 |
9 | ```bash
10 | cd 06-Data-Blocks
11 | ```
12 |
13 | 2. Make sure you still have your environment variables otherwise export them as before:
14 |
15 | ```bash
16 | export AWS_ACCESS_KEY_ID=your_value
17 | export AWS_SECRET_ACCESS_KEY=your_value
18 | ```
19 |
20 | 3. Initialize Terraform Plan, and Terraform Apply
21 |
22 | ```bash
23 | terraform init
24 | terraform plan
25 | terraform apply --auto-approve
26 | ```
27 |
28 | 4. Notice the `data` block in `main.tf`
29 |
30 | In `main.tf` we have a new block which is the `data` block. This block is used to get information as opposed to the resource block that is used to create resources. Here we're using the `data` block to retrieve the `id` of the Ubuntu 20.04 AMI.
31 |
32 | We're then referencing this `id` using the following format: `data.aws_ami.ubuntu.id`
33 |
34 | ```hcl
35 | resource "aws_instance" "webserver" {
36 | ami = data.aws_ami.ubuntu.id
37 | ```
38 |
39 | 5. Notice the output is moved to `output.tf`
40 |
41 | It's a common practice to move the `output` blocks to their own file. At minimum most Terraform configurations have a `main.tf` file, a `variables.tf` file, and an `output.tf` file.
42 |
43 | 6. Now go ahead and destroy the environment.
44 |
45 | ```bash
46 | terraform destroy --auto-approve
47 | ```
48 |
49 | > Congratulations you have finished this lab!
50 |
51 |
--------------------------------------------------------------------------------
/01-Basic-Commands/main.tf:
--------------------------------------------------------------------------------
1 | terraform {
2 | required_providers { # The `required_providers` block specifies the provider(s) needed for this Terraform configuration.
3 | docker = { # Here, we are requiring the `docker` provider.
4 | source = "kreuzwerker/docker" # This line specifies the source of the provider. In this case, it is the `kreuzwerker/docker` provider.
5 | version = "3.0.1" # This line specifies the version of the provider that we need.
6 | }
7 | }
8 | }
9 |
10 | provider "docker" {} # This `provider` block specifies that we want to use the `docker` provider.
11 |
12 | resource "docker_image" "nginx_image" { # This `resource` block creates a Docker image named `nginx_image` using the `nginx:1.23.3` image.
13 | name = "nginx:1.23.3"
14 | }
15 |
16 | resource "docker_container" "nginx_container" { # This `resource` block creates a Docker container named `nginx_container` based on the `nginx_image` image.
17 | name = "web-server" # This line specifies the name of the container.
18 | image = docker_image.nginx_image.image_id # This line references the `nginx_image` resource created earlier to get the image ID.
19 | ports { # This block specifies the ports to be exposed by the container.
20 | internal = 80 # The container's internal port 80 will be exposed.
21 | external = 8080 # The container's internal port 80 will be accessible on the host's port 8080.
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/08-Modules/main.tf:
--------------------------------------------------------------------------------
1 | terraform {
2 | required_providers {
3 | aws = {
4 | source = "hashicorp/aws"
5 | version = "4.19.0"
6 | }
7 | tls = {
8 | source = "hashicorp/tls"
9 | version = "4.0.0"
10 | }
11 | }
12 | }
13 |
14 | provider "aws" {
15 | region = var.region
16 | }
17 |
18 | data "aws_ami" "ubuntu" {
19 | most_recent = true
20 |
21 | filter {
22 | name = "name"
23 | values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"]
24 | }
25 |
26 | filter {
27 | name = "virtualization-type"
28 | values = ["hvm"]
29 | }
30 |
31 | owners = ["099720109477"] # Canonical https://ubuntu.com/server/docs/cloud-images/amazon-ec2
32 | }
33 |
34 | resource "aws_key_pair" "mykey" {
35 | key_name = var.my_aws_key
36 | public_key = module.tls.public_key_out
37 | }
38 |
39 | resource "aws_instance" "webserver" {
40 | ami = data.aws_ami.ubuntu.id
41 | instance_type = var.my_instance_type
42 | key_name = aws_key_pair.mykey.key_name
43 | vpc_security_group_ids = [aws_security_group.security_group1.id]
44 | }
45 |
46 | resource "aws_security_group" "security_group1" {
47 | ingress {
48 | cidr_blocks = ["0.0.0.0/0"]
49 | description = "SSH Ingress"
50 | from_port = 22
51 | to_port = 22
52 | protocol = "tcp"
53 | }
54 |
55 | egress {
56 | from_port = 0
57 | to_port = 0
58 | protocol = "-1"
59 | cidr_blocks = ["0.0.0.0/0"]
60 | }
61 | }
62 |
63 | module "tls" {
64 | source = "./modules/tls"
65 | algorithm = "RSA"
66 | rsa_bits = 4096
67 | }
--------------------------------------------------------------------------------
/.devcontainer/devcontainer.json:
--------------------------------------------------------------------------------
1 | // For format details, see https://aka.ms/devcontainer.json. For config options, see the
2 | // README at: https://github.com/devcontainers/templates/tree/main/src/docker-existing-dockerfile
3 | {
4 | "name": "Existing Dockerfile",
5 | // "image": "samgabrail/terraform101",
6 | "build": {
7 | // Update the 'dockerFile' property if you aren't using the standard 'Dockerfile' filename.
8 | "dockerfile": "Dockerfile"
9 | },
10 |
11 | // Features to add to the dev container. More info: https://containers.dev/features.
12 | // "features": {},
13 |
14 | // Use 'forwardPorts' to make a list of ports inside the container available locally.
15 | // "forwardPorts": [],
16 |
17 | // Uncomment the next line to run commands after the container is created - for example installing curl.
18 | // "postCreateCommand": "apt-get update && apt-get install -y curl",
19 |
20 | // Uncomment to use the Docker CLI from inside the container. See https://aka.ms/vscode-remote/samples/docker-from-docker.
21 | // "mounts": [
22 | // {
23 | // "source": "/var/run/docker.sock",
24 | // "target": "/var/run/docker-host.sock",
25 | // "type": "bind"
26 | // }
27 | // ]
28 |
29 | // Configure tool-specific properties.
30 | "customizations": {
31 | // Configure properties specific to VS Code.
32 | "vscode": {
33 | // Add the IDs of extensions you want installed when the container is created.
34 | "extensions": [
35 | "hashicorp.terraform"
36 | ]
37 | }
38 | }
39 |
40 | // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
41 | // "remoteUser": "root"
42 | }
43 |
--------------------------------------------------------------------------------
/09-A-Web-Server/main.tf:
--------------------------------------------------------------------------------
1 | terraform {
2 | required_providers {
3 | aws = {
4 | source = "hashicorp/aws"
5 | version = "4.19.0"
6 | }
7 | tls = {
8 | source = "hashicorp/tls"
9 | version = "4.0.0"
10 | }
11 | }
12 | }
13 |
14 | provider "aws" {
15 | region = var.region
16 | }
17 |
18 | data "aws_ami" "ubuntu" {
19 | most_recent = true
20 |
21 | filter {
22 | name = "name"
23 | values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"]
24 | }
25 |
26 | filter {
27 | name = "virtualization-type"
28 | values = ["hvm"]
29 | }
30 |
31 | owners = ["099720109477"] # Canonical https://ubuntu.com/server/docs/cloud-images/amazon-ec2
32 | }
33 |
34 | resource "aws_key_pair" "mykey" {
35 | key_name = var.my_aws_key
36 | public_key = module.tls.public_key_out
37 | }
38 |
39 | resource "aws_instance" "webserver" {
40 | ami = data.aws_ami.ubuntu.id
41 | instance_type = var.my_instance_type
42 | key_name = aws_key_pair.mykey.key_name
43 | vpc_security_group_ids = [aws_security_group.security_group1.id]
44 | user_data = file("install_libraries.sh")
45 | user_data_replace_on_change = true
46 | }
47 |
48 | resource "aws_security_group" "security_group1" {
49 | ingress {
50 | cidr_blocks = ["0.0.0.0/0"]
51 | description = "SSH Ingress"
52 | from_port = 22
53 | to_port = 22
54 | protocol = "tcp"
55 | }
56 | ingress {
57 | cidr_blocks = ["0.0.0.0/0"]
58 | description = "HTTP Ingress"
59 | from_port = 80
60 | to_port = 80
61 | protocol = "tcp"
62 |
63 | }
64 |
65 | egress {
66 | from_port = 0
67 | to_port = 0
68 | protocol = "-1"
69 | cidr_blocks = ["0.0.0.0/0"]
70 | }
71 | }
72 |
73 | module "tls" {
74 | source = "./modules/tls"
75 | }
76 |
--------------------------------------------------------------------------------
/07-Another-Provider/main.tf:
--------------------------------------------------------------------------------
1 | terraform {
2 | required_providers {
3 | aws = {
4 | source = "hashicorp/aws"
5 | version = "4.19.0"
6 | }
7 | tls = {
8 | source = "hashicorp/tls"
9 | version = "4.0.0"
10 | }
11 | }
12 | }
13 |
14 | provider "aws" {
15 | region = var.region
16 | }
17 |
18 | data "aws_ami" "ubuntu" {
19 | most_recent = true
20 |
21 | filter {
22 | name = "name"
23 | values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"]
24 | }
25 |
26 | filter {
27 | name = "virtualization-type"
28 | values = ["hvm"]
29 | }
30 |
31 | owners = ["099720109477"] # Canonical https://ubuntu.com/server/docs/cloud-images/amazon-ec2
32 | }
33 |
34 | resource "tls_private_key" "mykey" {
35 | algorithm = "RSA"
36 | rsa_bits = 4096
37 | }
38 |
39 | resource "aws_key_pair" "mykey" {
40 | key_name = "mykey.pem"
41 | public_key = tls_private_key.mykey.public_key_openssh
42 | }
43 |
44 | resource "aws_instance" "webserver" {
45 | ami = data.aws_ami.ubuntu.id
46 | instance_type = var.my_instance_type
47 | key_name = aws_key_pair.mykey.key_name
48 | vpc_security_group_ids = [aws_security_group.security_group1.id]
49 | }
50 |
51 | resource "aws_security_group" "security_group1" {
52 | ingress {
53 | cidr_blocks = ["0.0.0.0/0"]
54 | description = "SSH Ingress"
55 | from_port = 22
56 | to_port = 22
57 | protocol = "tcp"
58 | }
59 |
60 | egress {
61 | from_port = 0
62 | to_port = 0
63 | protocol = "-1"
64 | cidr_blocks = ["0.0.0.0/0"]
65 | }
66 | }
67 |
68 |
69 | # Getting the output from private key is via this command below:
70 |
71 | # terraform output -raw private_key
72 |
73 | # To ssh into the machine:
74 | # terraform output -raw private_key > myKey.pem
75 | # sudo chmod 400 myKey.pem
76 | # ssh -i myKey.pem ubuntu@$(terraform output -raw public_ip)
77 |
--------------------------------------------------------------------------------
/07-Another-Provider/guide.md:
--------------------------------------------------------------------------------
1 | # Another Provider
2 |
3 | So far we've created an EC2 instance but haven't ssh'd into it. In this lab we will use the TLS provider in addition to the AWS provider to create a public/private key pair to be used to ssh into the EC2 instance.
4 |
5 | ## Instructions
6 |
7 | 1. Change directory into the `07-Another-Provider` directory:
8 |
9 | ```bash
10 | cd 07-Another-Provider
11 | ```
12 |
13 | 2. Make sure you still have your environment variables otherwise export them as before:
14 |
15 | ```bash
16 | export AWS_ACCESS_KEY_ID=your_value
17 | export AWS_SECRET_ACCESS_KEY=your_value
18 | ```
19 |
20 | 3. Initialize Terraform Plan, and Terraform Apply
21 |
22 | ```bash
23 | terraform init
24 | terraform plan
25 | terraform apply --auto-approve
26 | ```
27 |
28 | Notice the `private_key` in the output is marked as sensitive because we specified that in the `output.tf` file.
29 |
30 | 4. Examine `main.tf`
31 |
32 | In `main.tf` we now have another provider `tls`. We use the resource `tls_private_key` to create a private/public key pair. Then we create an `aws_key_pair` resource in AWS referencing the public key with: `tls_private_key.mykey.public_key_openssh`
33 |
34 | Also, notice that we created a security group to allow ssh inbound to the instance. This is done with the aws_security_group resource. You then reference it in the aws_instance resource like this:
35 |
36 | ```hcl
37 | vpc_security_group_ids = [aws_security_group.security_group1.id]
38 | ```
39 |
40 | The square brackets are used because vpc_security_group_ids requires a list of security group ids.
41 |
42 | 5. Examine the state file
43 |
44 | Notice that the private key shows up in the state file! This is a very important concept to understant so you would secure your statefile.
45 |
46 | 6. SSH into the EC2 instance
47 |
48 | We can get the value of the private key and store it in a file on disk then we can change the permissions on the file and finally ssh.
49 |
50 | ```bash
51 | terraform output -raw private_key > myKey.pem
52 | sudo chmod 400 myKey.pem
53 | ssh -i myKey.pem ubuntu@$(terraform output -raw public_ip)
54 | ```
55 |
56 | 7. Now go ahead and destroy the environment.
57 |
58 | ```bash
59 | terraform destroy --auto-approve
60 | ```
61 |
62 | > Congratulations you have finished this lab!
63 |
64 |
--------------------------------------------------------------------------------
/07-Another-Provider/.terraform.lock.hcl:
--------------------------------------------------------------------------------
1 | # This file is maintained automatically by "terraform init".
2 | # Manual edits may be lost in future updates.
3 |
4 | provider "registry.terraform.io/hashicorp/aws" {
5 | version = "4.19.0"
6 | constraints = "4.19.0"
7 | hashes = [
8 | "h1:4vAZv9/3q5z78CV+YAumfuaoSNSNwAXDEhI/XnGVM5E=",
9 | "zh:22820bfa0065f583298015367f8dc015dffa5b19b76dbd78ecf5da8d7d599573",
10 | "zh:31a5c5fade4bd30dbc2b15f448cebb9ed527793c607e8687d3b2101bcf2c4471",
11 | "zh:37c9e469e51aa835a5542510561397541de08b62fc15292588382932624fcf88",
12 | "zh:398bfe1ba7428ef03293c6618067ddd8c0aaae8bbe764177ae951259228af724",
13 | "zh:4610f5a93ef956103d719ae73872a52ecd6cb321452c26a879896348bc27eed9",
14 | "zh:4a0d570dc5f01f41538b4eb70086a00dfb25c5d00fd27c950ac209d3609486f6",
15 | "zh:4fb65ce84801f82a3beb4e2cb72c5d52ca04d4717ed3890b206da346f02d5def",
16 | "zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425",
17 | "zh:9bb3919bd6d94fb22025540f0c1db5eceec8927bd71b8fbdcd295609c999065f",
18 | "zh:ce2623a13f74677cdb948607e456ce00407c57333b8310d5c9d053fc3defbc78",
19 | "zh:e0d57e8784e6ccfa96fdd07ae1ddcc947be242bc11e7a5dd16b520b4204e0d09",
20 | "zh:f988b7c37e95a5b3a493a6b9dcc5ed270136f97d5c0effa84a51940f71626c12",
21 | ]
22 | }
23 |
24 | provider "registry.terraform.io/hashicorp/tls" {
25 | version = "4.0.0"
26 | constraints = "4.0.0"
27 | hashes = [
28 | "h1:kOrvJIaved9HipxnVcipaOv9zILQ+mU96f5XrNqXiRA=",
29 | "zh:0e274781301a67dc18b40b8544714f338759ce0170e95e79430b9a05b447aece",
30 | "zh:1dbbfae8a39ad6109036fa72dff246eb9b8a02ef5b34f9cdc8b4120c9b2de81e",
31 | "zh:40ccf9da97268cd8ddb49ef0349ddd0e0b97dd127522035d05156803234634d4",
32 | "zh:437c030559b6352a49f6e6430415e0cfbd2668712c9155fa9b54dc2e6f8267eb",
33 | "zh:50c840c579270e649d42b4276bbfacf2d3b5beae1f0dcabf0b5f535b2ce7975c",
34 | "zh:6b5caf6172521bfd1beba067b4ce71793a85abb1b0f1d96a89cf54c5b5fd1223",
35 | "zh:98b68106837b3e8577f239a8562387e76d408ff49d08647103664e75bc193427",
36 | "zh:cc5d9db1c74a2f135563d8706b4003d9b0e344dc1d17417977438ffa15db5938",
37 | "zh:de39da56477abc52f0fff7837fbd10063f8508d9fcaf377d1e6d775d0390755a",
38 | "zh:f3c8509e41f4dee8b54c2c4c1b335279de044cb8bea363b5442ac368c6bdee15",
39 | "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c",
40 | "zh:f7931dda4377c6548e5fc7afddab03230ac9b42380908932542dea7661e0f078",
41 | ]
42 | }
43 |
--------------------------------------------------------------------------------
/09-A-Web-Server/guide.md:
--------------------------------------------------------------------------------
1 | # A Web Server
2 |
3 | The concept of modules is to re-use code by building bigger infrastructure constructs using modules as building blocks. We will move the TLS resource into a module. Typically you won't only put one resource into a module, but a collection of resources. We're only doing this to show a simple exmaple.
4 |
5 | ## Instructions
6 |
7 | 1. Change directory into the `09-A-Web-Server` directory:
8 |
9 | ```bash
10 | cd 09-A-Web-Server
11 | ```
12 |
13 | 2. Make sure you still have your environment variables otherwise export them as before:
14 |
15 | ```bash
16 | export AWS_ACCESS_KEY_ID=your_value
17 | export AWS_SECRET_ACCESS_KEY=your_value
18 | ```
19 |
20 | 3. Initialize Terraform Plan, and Terraform Apply
21 |
22 | Notice how Terraform initializes our new module.
23 |
24 | ```bash
25 | terraform init
26 | terraform plan
27 | terraform apply --auto-approve
28 | ```
29 |
30 | Now in a browser tab paste the public IP to see your new and shiny web server running.
31 |
32 | 4. Examine `main.tf`
33 |
34 | We've included two additional things:
35 |
36 | - Updated the security group to include port 80 to access our web server
37 |
38 | ```hcl
39 | ...truncated
40 | ingress {
41 | cidr_blocks = ["0.0.0.0/0"]
42 | description = "HTTP Ingress"
43 | from_port = 80
44 | to_port = 80
45 | protocol = "tcp"
46 | }
47 | ...truncated
48 | ```
49 |
50 | - Added the user_data field
51 |
52 | Here the `user_data` field uses the `file()` function to call on the `install_libraries.sh` script. The `user_data_replace_on_change = true` property means that if Terraform senses a change in the content of `user_data` then it will rebuild the EC2 instance.
53 |
54 | ```hcl
55 | resource "aws_instance" "webserver" {
56 | ami = data.aws_ami.ubuntu.id
57 | instance_type = var.my_instance_type
58 | key_name = aws_key_pair.mykey.key_name
59 | vpc_security_group_ids = [aws_security_group.security_group1.id]
60 | user_data = file("install_libraries.sh")
61 | user_data_replace_on_change = true
62 | }
63 | ```
64 |
65 | 5. Examine the `install_libraries.sh` script
66 |
67 | This is the file that the EC2 instance uses to configure our web server. We install an nginx webserver and create a simple `index.html` page.
68 |
69 | 6. Now go ahead and destroy the environment.
70 |
71 | ```bash
72 | terraform destroy --auto-approve
73 | ```
74 |
75 | > Congratulations you have finished this lab!
76 |
77 |
--------------------------------------------------------------------------------
/08-Modules/guide.md:
--------------------------------------------------------------------------------
1 | # Modules
2 |
3 | The concept of modules is to re-use code by building bigger infrastructure constructs using modules as building blocks. We will move the TLS resource into a module. Typically you won't only put one resource into a module, but a collection of resources. We're only doing this to show a simple exmaple.
4 |
5 | ## Instructions
6 |
7 | 1. Change directory into the `08-Modules` directory:
8 |
9 | ```bash
10 | cd 08-Modules
11 | ```
12 |
13 | 2. Make sure you still have your environment variables otherwise export them as before:
14 |
15 | ```bash
16 | export AWS_ACCESS_KEY_ID=your_value
17 | export AWS_SECRET_ACCESS_KEY=your_value
18 | ```
19 |
20 | 3. Initialize Terraform Plan, and Terraform Apply
21 |
22 | Notice how Terraform initializes our new module.
23 |
24 | ```bash
25 | terraform init
26 | terraform plan
27 | terraform apply --auto-approve
28 | ```
29 |
30 | Notice that everything works the same as before.
31 |
32 | 4. Examine `main.tf`
33 |
34 | Now the directory where the `main.tf` file exists is considered the root module. So far in this tutorial we've been doing everything in the root module.
35 |
36 | From the root module we're calling our child `tls` module:
37 |
38 | ```hcl
39 | module "tls" {
40 | source = "./modules/tls"
41 | algorithm = "RSA"
42 | rsa_bits = 4096
43 | }
44 | ```
45 |
46 | We need to specify the source path of the module along with the necessary input variables into the module.
47 |
48 | We can also use a module's output by referencing the module using the syntax `mocule.. as shown below:
49 |
50 | ```hcl
51 | resource "aws_key_pair" "mykey" {
52 | key_name = var.my_aws_key
53 | public_key = module.tls.public_key_out
54 | }
55 | ```
56 |
57 | 5. Examine the `tls` module
58 |
59 | Now take a look at the `tls` directory under the `modules` directory. As a good practice, you should include at least 5 files in a module:
60 | - README.md
61 | - LICENSE
62 | - main.tf
63 | - variables.tf
64 | - outputs.tf
65 |
66 | Notice how there is nothing special about a module. It's the same Terraform code that we've learned so far.
67 |
68 | 6. Flow of Data
69 |
70 | Notice how the output gets passed from the tls module to the root module and out to the CLI. Check the output of the tls module:
71 |
72 | ```hcl
73 | output "private_key" {
74 | value = tls_private_key.mykey.private_key_pem
75 | sensitive = true
76 | }
77 | output "public_key_out" {
78 | value = tls_private_key.mykey.public_key_openssh
79 | }
80 | ```
81 |
82 | Check the output of the root module:
83 |
84 | ```hcl
85 | output "public_ip" {
86 | value = aws_instance.webserver.public_ip
87 | description = "EC2 Public IP"
88 | }
89 | output "private_key" {
90 | value = module.tls.private_key
91 | sensitive = true
92 | }
93 | ```
94 |
95 | 7. Now go ahead and destroy the environment.
96 |
97 | ```bash
98 | terraform destroy --auto-approve
99 | ```
100 |
101 | > Congratulations you have finished this lab!
102 |
103 |
--------------------------------------------------------------------------------
/02-Lock-and-State-Files/guide.md:
--------------------------------------------------------------------------------
1 | # Lock and State Files
2 |
3 | In this lab we learn about the Lock and State files.
4 |
5 | ## Instructions
6 |
7 | 1. Change directory into the 02-Lock-and-State-Files directory:
8 |
9 | ```bash
10 | cd 02-Lock-and-State-Files
11 | ```
12 |
13 | 2. Initialize and Terraform Apply
14 |
15 | ```bash
16 | terraform init
17 | terraform apply --auto-approve
18 | ```
19 |
20 | 3. Examine the `.terraform.lock.hcl` file
21 |
22 | The `.terraform.lock.hcl` file is a generated file that Terraform creates when it installs provider dependencies for a Terraform configuration. It contains a list of all the provider dependencies, including their version constraints, that were installed for the Terraform configuration.
23 |
24 | The purpose of the `.terraform.lock.hcl` file is to ensure that the exact same versions of providers are installed each time the Terraform configuration is applied, regardless of the environment where it is applied. This helps to prevent unexpected changes or failures due to version differences in the provider dependencies.
25 |
26 | When Terraform applies a configuration, it reads the `.terraform.lock.hcl` file to determine which provider dependencies to use, and then installs them if necessary. If the `.terraform.lock.hcl` file is not present, Terraform will attempt to download and install the latest version of each provider dependency, which may result in changes or failures if the latest version is incompatible with the configuration.
27 |
28 | It is recommended to include the `.terraform.lock.hcl` file in version control along with the Terraform configuration to ensure that all team members and deployment environments are using the same provider versions.
29 |
30 | 4. Examine the `terraform.tfstate` file
31 |
32 | The `terraform.tfstate` file is a generated file that Terraform uses to keep track of the current state of the resources managed by a Terraform configuration. This file contains information about the resources that were created or modified, their current state, and any metadata that is associated with them.
33 |
34 | The purpose of the `terraform.tfstate` file is to enable Terraform to determine what changes need to be made to the resources when a configuration is applied. When Terraform applies a configuration, it reads the current state from the `terraform.tfstate` file, compares it to the desired state specified in the configuration, and then creates, modifies, or deletes resources as necessary to achieve the desired state.
35 |
36 | The `terraform.tfstate` file is an important part of the Terraform workflow because it enables Terraform to perform resource management and maintain state over time. Without the `terraform.tfstate` file, Terraform would not be able to determine which resources need to be created, modified, or deleted, and it would not be able to maintain state across multiple runs of the same configuration.
37 |
38 | It is important to store the `terraform.tfstate` file securely and consistently, since it contains sensitive information such as resource IDs, passwords, and access keys. Terraform supports several ways of storing the `terraform.tfstate` file, including local file storage, remote storage solutions like AWS S3 and Azure Blob Storage, and Terraform Cloud.
39 |
40 | 5. Destroy the environment and re-examine the state file to see what changed. Be very careful when using the `--auto-approve` flag with `terraform apply` or `terraform destroy`. This should not be used in production as it will override the prompt.
41 |
42 | ```bash
43 | terraform destroy --auto-approve
44 | ```
45 |
46 | 6. Examine the Docker provider documentation
47 |
48 | https://registry.terraform.io/providers/kreuzwerker/docker/latest/docs
49 |
50 | > Congratulations you have finished this lab!
51 |
52 |
--------------------------------------------------------------------------------
/01-Basic-Commands/guide.md:
--------------------------------------------------------------------------------
1 | # Basic Commands
2 |
3 | In this lab we learn the very basic Terraform commands.
4 |
5 | ## Instructions
6 |
7 | 1. Change directory into the 01-Basic-Commands directory:
8 |
9 | ```bash
10 | cd 01-Basic-Commands
11 | ```
12 |
13 | 2. Run the following commands
14 |
15 | ```bash
16 | terraform version
17 | terraform -help
18 | terraform init
19 | terraform fmt
20 | terraform validate
21 | terraform plan
22 | terraform apply
23 | terraform output
24 | ```
25 |
26 | Here is the explanation of each of these commands:
27 | - `terraform version:` This command displays the currently installed version of Terraform. It is used to verify which version of Terraform you have installed and to ensure that the correct version is being used for your infrastructure.
28 |
29 | - `terraform -help:` This command displays a list of available commands and options for Terraform. It is used to get help with Terraform commands and options and to learn how to use Terraform.
30 |
31 | - `terraform init:` This command initializes a new or existing Terraform working directory. It is used to download and install the required provider plugins, configure the backend, and prepare the working directory for Terraform operations.
32 |
33 | - `terraform fmt:` This command is used to format the Terraform configuration files in a standard and consistent way. It is used to automatically update and standardize the formatting of your Terraform code to make it easier to read and maintain.
34 |
35 | - `terraform validate:` This command is used to validate the syntax and configuration of your Terraform code. It is used to check if your code follows the correct syntax and format and can catch errors early in the development process.
36 |
37 | - `terraform plan:` This command generates an execution plan that shows what Terraform will do when you apply your configuration. It is used to preview the changes that will be made to your infrastructure and to detect any potential problems before applying the changes.
38 |
39 | - `terraform apply:` This command applies the changes to your infrastructure according to your Terraform configuration. It is used to create, modify, or delete resources in your infrastructure.
40 |
41 | - `terraform output:` This command displays the outputs of your Terraform configuration. It is used to retrieve the values of any output variables that were defined in your Terraform code.
42 |
43 | 3. Run `docker ps` and `docker images` to check the newly created container
44 |
45 | ```bash
46 | docker ps
47 | docker images
48 | ```
49 |
50 | 4. Go to the nginx URL
51 | If port 8080 doesn't get forwarded automatically, then go to the `PORTS` tab and add port 8080 manually.
52 |
53 | Now click on the Globe Icon under Lcal Address in the `PORTS` tab to open the URL for nginx.
54 |
55 | 5. Now destroy the environment with `terraform destroy`
56 |
57 | ```bash
58 | terraform destroy
59 | ```
60 |
61 | > Congratulations you have finished this lab!
62 |
63 | ## Lab Code Explanation
64 |
65 | Terraform is an infrastructure-as-code tool that allows you to define and manage infrastructure resources in a declarative way. This Terraform configuration sets up a Docker container running the Nginx web server with port forwarding from port 8080 on the host machine to port 80 inside the container.
66 |
67 |
68 | Let's go through the code line by line:
69 |
70 | ```hcl
71 | terraform {
72 | required_providers { # The `required_providers` block specifies the provider(s) needed for this Terraform configuration.
73 | docker = { # Here, we are requiring the `docker` provider.
74 | source = "kreuzwerker/docker" # This line specifies the source of the provider. In this case, it is the `kreuzwerker/docker` provider.
75 | version = "3.0.1" # This line specifies the version of the provider that we need.
76 | }
77 | }
78 | }
79 |
80 | provider "docker" {} # This `provider` block specifies that we want to use the `docker` provider.
81 |
82 | resource "docker_image" "nginx_image" { # This `resource` block creates a Docker image named `nginx_image` using the `nginx:1.23.3` image.
83 | name = "nginx:1.23.3"
84 | }
85 |
86 | resource "docker_container" "nginx_container" { # This `resource` block creates a Docker container named `nginx_container` based on the `nginx_image` image.
87 | name = "web-server" # This line specifies the name of the container.
88 | image = docker_image.nginx_image.image_id # This line references the `nginx_image` resource created earlier to get the image ID.
89 | ports { # This block specifies the ports to be exposed by the container.
90 | internal = 80 # The container's internal port 80 will be exposed.
91 | external = 8080 # The container's internal port 80 will be accessible on the host's port 8080.
92 | }
93 | }
94 | ```
95 |
--------------------------------------------------------------------------------