├── .gitignore ├── LICENSE ├── README.md ├── assets └── img │ ├── santi_terraform.jpg │ └── terraform_gif.gif ├── ex00_terraform_intro ├── .terraform.lock.hcl ├── README.md ├── main.tf ├── outputs.tf ├── terraform.tfvars.json └── variables.tf ├── ex01_packer_aws_ami ├── README.md ├── cool-ubuntu-aws-ami.json └── scripts │ └── install-docker.sh ├── ex02_terraform_basics ├── .terraform.lock.hcl ├── README.md ├── dev.tfvars.json ├── main.tf ├── output.tf └── variables.tf ├── ex03_terraform_backend ├── .terraform.lock.hcl ├── backend.tf ├── main.tf └── variables.tf ├── ex03_terraform_backend_01_create_bucket ├── .terraform.lock.hcl ├── README.md ├── main.tf └── variables.tf ├── ex03_terraform_backend_02_create_resources ├── .terraform.lock.hcl ├── README.md ├── backend.tf ├── main.tf └── variables.tf ├── ex04_terraform_vpc_with_subnets_and_ec2 ├── .terraform.lock.hcl ├── README.md ├── dev.tfvars.json ├── main.tf ├── output.tf └── variables.tf ├── ex05_terraform_simple_lambda ├── .terraform.lock.hcl ├── buckets.tf ├── createresources ├── index.js ├── lambda.zip ├── lambdas.tf ├── mainvars.tf └── vars.tf ├── ex06_modules_00 ├── .terraform.lock.hcl ├── main.tf ├── modules │ └── bucket │ │ ├── main.tf │ │ ├── outputs.tf │ │ └── variables.tf ├── outputs.tf └── variables.tf ├── ex06_modules_01 ├── .terraform.lock.hcl ├── bucket │ ├── main.tf │ ├── outputs.tf │ └── variables.tf ├── main.tf ├── outputs.tf ├── subnet │ ├── main.tf │ ├── outputs.tf │ └── variabes.tf ├── variables.tf └── vpc │ ├── main.tf │ ├── outputs.tf │ └── variables.tf ├── ex07_loops_with_lists ├── count │ ├── .terraform.lock.hcl │ ├── main.tf │ └── result_plan.txt └── for_each │ ├── .terraform.lock.hcl │ ├── main.tf │ └── result_plan.txt ├── ex07_loops_with_maps ├── count │ ├── .terraform.lock.hcl │ ├── main.tf │ └── result_plan.txt └── for_each │ ├── .terraform.lock.hcl │ ├── main.tf │ └── result_plan.txt └── other_examples ├── alb_to_ec2 ├── dev.tfvars.json ├── main.tf ├── output.tf └── variables.tf ├── lambda_python_api ├── Makefile ├── lambda-layers │ ├── Makefile │ └── fastapi │ │ ├── Makefile │ │ └── requirements.txt ├── src │ ├── __init__.py │ └── lambdas │ │ ├── __init__.py │ │ └── api │ │ └── main.py └── terraform │ ├── backend.tf │ ├── lambda.tf │ ├── locals.tf │ ├── provider.tf │ └── variables.tf └── multiple_instances_based_on_tags ├── .terraform.lock.hcl ├── copy.terraform.tfvars ├── main.tf ├── outputs.tf ├── provider.tf ├── terraform.tfvars └── variables.tf /.gitignore: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # OWN IGNORES 3 | ################################################################################ 4 | .vscode 5 | temp.* 6 | .DS_Store 7 | *.zip 8 | 9 | # To ignore Lambda Layers files (like Python dependencies) 10 | modules 11 | 12 | 13 | ################################################################################ 14 | # PACKER IGNORES 15 | ################################################################################ 16 | # Cache objects 17 | packer_cache/ 18 | 19 | # Crash log 20 | crash.log 21 | 22 | # For built boxes 23 | *.box 24 | 25 | ### Packer Patch ### 26 | # ignore temporary output files 27 | output-*/ 28 | 29 | ################################################################################ 30 | # TERRAFORM IGNORES 31 | ################################################################################ 32 | ### Terraform ### 33 | # Local .terraform directories 34 | **/.terraform/* 35 | 36 | # .tfstate files 37 | *.tfstate 38 | *.tfstate.* 39 | 40 | # Crash log files 41 | 42 | # Ignore any .tfvars files that are generated automatically for each Terraform run. Most 43 | # .tfvars files are managed as part of configuration and so should be included in 44 | # version control. 45 | # 46 | # example.tfvars 47 | 48 | # Ignore override files as they are usually used to override resources locally and so 49 | # are not checked in 50 | override.tf 51 | override.tf.json 52 | *_override.tf 53 | *_override.tf.json 54 | 55 | 56 | ################################################################################ 57 | # PYTHON IGNORES 58 | ################################################################################ 59 | 60 | # Byte-compiled / optimized / DLL files 61 | __pycache__/ 62 | *.py[cod] 63 | *$py.class 64 | 65 | # C extensions 66 | *.so 67 | 68 | # Distribution / packaging 69 | .Python 70 | build/ 71 | develop-eggs/ 72 | dist/ 73 | downloads/ 74 | eggs/ 75 | .eggs/ 76 | # lib/ 77 | lib64/ 78 | parts/ 79 | sdist/ 80 | var/ 81 | wheels/ 82 | share/python-wheels/ 83 | *.egg-info/ 84 | .installed.cfg 85 | *.egg 86 | MANIFEST 87 | 88 | # PyInstaller 89 | # Usually these files are written by a python script from a template 90 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 91 | *.manifest 92 | *.spec 93 | 94 | # Installer logs 95 | pip-log.txt 96 | pip-delete-this-directory.txt 97 | 98 | # Unit test / coverage reports 99 | htmlcov/ 100 | .tox/ 101 | .nox/ 102 | .coverage 103 | .coverage.* 104 | .cache 105 | nosetests.xml 106 | coverage.xml 107 | *.cover 108 | *.py,cover 109 | .hypothesis/ 110 | .pytest_cache/ 111 | cover/ 112 | 113 | # Translations 114 | *.mo 115 | *.pot 116 | 117 | # Django stuff: 118 | *.log 119 | local_settings.py 120 | db.sqlite3 121 | db.sqlite3-journal 122 | 123 | # Flask stuff: 124 | instance/ 125 | .webassets-cache 126 | 127 | # Scrapy stuff: 128 | .scrapy 129 | 130 | # Sphinx documentation 131 | docs/_build/ 132 | 133 | # PyBuilder 134 | .pybuilder/ 135 | target/ 136 | 137 | # Jupyter Notebook 138 | .ipynb_checkpoints 139 | 140 | # IPython 141 | profile_default/ 142 | ipython_config.py 143 | 144 | # pyenv 145 | # For a library or package, you might want to ignore these files since the code is 146 | # intended to run in multiple environments; otherwise, check them in: 147 | # .python-version 148 | 149 | # pipenv 150 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 151 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 152 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 153 | # install all needed dependencies. 154 | #Pipfile.lock 155 | 156 | # poetry 157 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 158 | # This is especially recommended for binary packages to ensure reproducibility, and is more 159 | # commonly ignored for libraries. 160 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 161 | #poetry.lock 162 | 163 | # pdm 164 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. 165 | #pdm.lock 166 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it 167 | # in version control. 168 | # https://pdm.fming.dev/#use-with-ide 169 | .pdm.toml 170 | 171 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm 172 | __pypackages__/ 173 | 174 | # Celery stuff 175 | celerybeat-schedule 176 | celerybeat.pid 177 | 178 | # SageMath parsed files 179 | *.sage.py 180 | 181 | # Environments 182 | .env 183 | .venv 184 | env/ 185 | venv/ 186 | ENV/ 187 | env.bak/ 188 | venv.bak/ 189 | 190 | # Spyder project settings 191 | .spyderproject 192 | .spyproject 193 | 194 | # Rope project settings 195 | .ropeproject 196 | 197 | # mkdocs documentation 198 | /site 199 | 200 | # mypy 201 | .mypy_cache/ 202 | .dmypy.json 203 | dmypy.json 204 | 205 | # Pyre type checker 206 | .pyre/ 207 | 208 | # pytype static type analyzer 209 | .pytype/ 210 | 211 | # Cython debug symbols 212 | cython_debug/ 213 | 214 | # PyCharm 215 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 216 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 217 | # and can be added to the global gitignore or merged into this file. For a more nuclear 218 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 219 | #.idea/ 220 | 221 | 222 | ################################################################################ 223 | # NODEJS IGNORES 224 | ################################################################################ 225 | # Logs 226 | logs 227 | *.log 228 | npm-debug.log* 229 | yarn-debug.log* 230 | yarn-error.log* 231 | lerna-debug.log* 232 | .pnpm-debug.log* 233 | 234 | # Diagnostic reports (https://nodejs.org/api/report.html) 235 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 236 | 237 | # Runtime data 238 | pids 239 | *.pid 240 | *.seed 241 | *.pid.lock 242 | 243 | # Directory for instrumented libs generated by jscoverage/JSCover 244 | lib-cov 245 | 246 | # Coverage directory used by tools like istanbul 247 | coverage 248 | *.lcov 249 | 250 | # nyc test coverage 251 | .nyc_output 252 | 253 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 254 | .grunt 255 | 256 | # Bower dependency directory (https://bower.io/) 257 | bower_components 258 | 259 | # node-waf configuration 260 | .lock-wscript 261 | 262 | # Compiled binary addons (https://nodejs.org/api/addons.html) 263 | build/Release 264 | 265 | # Dependency directories 266 | node_modules/ 267 | jspm_packages/ 268 | 269 | # Snowpack dependency directory (https://snowpack.dev/) 270 | web_modules/ 271 | 272 | # TypeScript cache 273 | *.tsbuildinfo 274 | 275 | # Optional npm cache directory 276 | .npm 277 | 278 | # Optional eslint cache 279 | .eslintcache 280 | 281 | # Optional stylelint cache 282 | .stylelintcache 283 | 284 | # Microbundle cache 285 | .rpt2_cache/ 286 | .rts2_cache_cjs/ 287 | .rts2_cache_es/ 288 | .rts2_cache_umd/ 289 | 290 | # Optional REPL history 291 | .node_repl_history 292 | 293 | # Output of 'npm pack' 294 | *.tgz 295 | 296 | # Yarn Integrity file 297 | .yarn-integrity 298 | 299 | # dotenv environment variable files 300 | .env 301 | .env.development.local 302 | .env.test.local 303 | .env.production.local 304 | .env.local 305 | 306 | # parcel-bundler cache (https://parceljs.org/) 307 | .cache 308 | .parcel-cache 309 | 310 | # Next.js build output 311 | .next 312 | out 313 | 314 | # Nuxt.js build / generate output 315 | .nuxt 316 | dist 317 | 318 | # Gatsby files 319 | .cache/ 320 | # Comment in the public line in if your project uses Gatsby and not Next.js 321 | # https://nextjs.org/blog/next-9-1#public-directory-support 322 | # public 323 | 324 | # vuepress build output 325 | .vuepress/dist 326 | 327 | # vuepress v2.x temp and cache directory 328 | .temp 329 | .cache 330 | 331 | # Docusaurus cache and generated files 332 | .docusaurus 333 | 334 | # Serverless directories 335 | .serverless/ 336 | 337 | # FuseBox cache 338 | .fusebox/ 339 | 340 | # DynamoDB Local files 341 | .dynamodb/ 342 | 343 | # TernJS port file 344 | .tern-port 345 | 346 | # Stores VSCode versions used for testing VSCode extensions 347 | .vscode-test 348 | 349 | # yarn v2 350 | .yarn/cache 351 | .yarn/unplugged 352 | .yarn/build-state.yml 353 | .yarn/install-state.gz 354 | .pnp.* 355 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Santiago Garcia Arango 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # :hammer: TERRAFORM-PLAYGROUND :hammer: 2 | 3 | Learning Terraform with AWS examples. 4 | 5 | This repository covers a simple-learning approach for Terraform (90%) and Packer (10%) with AWS.
6 | 7 | We will cover important Infrastructure as Code (IaC) concepts that support the best DevOps practices.
8 | 9 |
10 | 11 | ## General Overview of this Repository :swimmer: 12 | 13 | This repository is my own learning-playground for Terraform-based projects. It has different examples and the overall idea is to have fun with Infrastructure as Code projects towards AWS.
14 | 15 | The examples are simple, but they are a good way to learn terraform from "scratch".
16 | 17 | ## Dependencies :vertical_traffic_light: 18 | 19 | My advice is to primary understand the way Terraform works with basic tutorials, and then try to develop amazing project ideas based on these examples.
20 | 21 | ### Software dependencies (based on project) 22 | 23 | - [Visual Studio Code](https://code.visualstudio.com/)
24 | Visual Studio Code is my main code editor for high-level programming. This is not absolutely necessary, but from my experience, it gives us a great performance and we can link it with Git and GitHub easily.
25 | 26 | - [Terraform](https://www.terraform.io)
27 | Terraform is a way to codify, automate, provision and version cloud APIs into declarative configuration files. The main purpose of Terraform is to create IaC for provisioning amazing infrastructure to different clouds.
28 | 29 | - [Packer](https://www.packer.io)
30 | Packer allows us to create identical machine images for multiple platforms from a single source configuration. We will use it to create AWS AMIs to launch custom EC2 images.
31 | 32 | ## Important Terraform Remarks :headphones: 33 | 34 | Some important notes to keep in mind for the usage of Terraform are: 35 | 36 | ### Install Terraform Bin/Exe 37 | 38 | To install Terraform, please go to [Download Terraform](https://www.terraform.io/downloads) and install the specific version for your OS. Remember to add the specific path to the binary, so that Terraform CLI can be used correctly.
39 | 40 | ### Terraform Files 41 | 42 | Terraform files usually have the `.tf` extension and there is also the `.tf.json` convention for a JSON-based variant of the language. See extra details on [Terraform Files and Directories](https://www.terraform.io/language/files).
43 | 44 | ### Terraform State 45 | 46 | One of the most important files are the `terraform.tfstate` and `terraform.tfstate.backup`, which determine the state and they can be stored locally or remotely. These files contain the state of the infrastructure and configurations related to the IaC. They also maps real world resources to the configuration and keep track of extra relevant information. You can learn more about the state in [Terraform State](https://www.terraform.io/language/state) 47 | 48 | ### Terraform Dependency Lock 49 | 50 | Another important file is the `.terraform.lock.hcl`, which is the [Dependency Lock File](https://www.terraform.io/language/files/dependency-lock) and it tracks the provider dependencies.
51 | 52 | ### Terraform Commands 53 | 54 | - Initialize Terraform directory and downloads providers: 55 | 56 | ```bash 57 | terraform init 58 | ``` 59 | 60 | - Initialize Terraform directory and do not download providers: 61 | 62 | ```bash 63 | terraform init --get-plugins=false 64 | ``` 65 | 66 | - Download and update root modules: 67 | 68 | ```bash 69 | terraform get 70 | ``` 71 | 72 | - Create an execution plan: 73 | 74 | ```bash 75 | terraform plan 76 | ``` 77 | 78 | - Create an execution plan only for a targeted resource: 79 | 80 | ```bash 81 | terraform plan -target="random_cool_resource.random_cool_resource_name" 82 | ``` 83 | 84 | - Create a destroy plan: 85 | 86 | ```bash 87 | terraform plan -destroy 88 | ``` 89 | 90 | - Execute (apply) changes in the real environment: 91 | 92 | ```bash 93 | terraform apply 94 | ``` 95 | 96 | - Execute (apply) changes in the real environment with specific variable file: 97 | 98 | ```bash 99 | terraform apply --var-file dev.tfvars.json 100 | ``` 101 | 102 | - Execute (apply) changes only for a targeted resource: 103 | 104 | ```bash 105 | terraform apply -target="random_cool_resource.random_cool_resource_name" 106 | ``` 107 | 108 | - Destroy all resources: 109 | 110 | ```bash 111 | terraform destroy 112 | ``` 113 | 114 | - Destroy only a targeted resource: 115 | 116 | ```bash 117 | terraform destroy -target="random_cool_resource.random_cool_resource_name" 118 | ``` 119 | 120 | - Refresh the state of Terraform state file with real environment: 121 | 122 | ```bash 123 | terraform refresh 124 | ``` 125 | 126 | - Terraform workspace commands: 127 | 128 | ```bash 129 | terraform workspace new 130 | terraform workspace select 131 | terraform workspace list 132 | terraform workspace show 133 | terraform workspace delete 134 | ``` 135 | 136 | - Format Terraform files into HCL canonical structure: 137 | 138 | ```bash 139 | terraform fmt 140 | ``` 141 | 142 | - Validate Terraform files: 143 | 144 | ```bash 145 | terraform validate 146 | ``` 147 | 148 | - Create graph of resources and its dependencies: 149 | 150 | ```bash 151 | terraform graph 152 | # Copy the output to "http://webgraphviz.com" 153 | ``` 154 | 155 | - Enumerates all outputs from the root module: 156 | 157 | ```bash 158 | terraform output 159 | ``` 160 | 161 | - Enumerates an specific output from the root module: 162 | 163 | ```bash 164 | terraform output 165 | ``` 166 | 167 | - Terraform state commands: 168 | ```bash 169 | terraform state list 170 | terraform state list aws_instance.my_cool_ec2 171 | terraform state show aws_instance.my_cool_ec2 172 | terraform state pull 173 | terraform state push 174 | terraform state mv 175 | terraform state rm 176 | ``` 177 | 178 | ## Important Packer Remarks :headphones: 179 | 180 | Some important notes to keep in mind for the usage of Packer are: 181 | 182 | ### Install Packer Bin/Exe 183 | 184 | To install Packer, please go to [Download Packer](https://www.packer.io/downloads) and install the specific version for your OS. Remember to add the specific path to the binary, so that Packer CLI can be used correctly.
185 | 186 | ### How the AMI is created 187 | 188 | When the AMI process is being executed, it usually creates an EC2 instance called `Packer Builder`. Keep this in mind if you want to do extra debugging related to the AMI creation on AWS.
189 | 190 | ### Packer Commands 191 | 192 | - Validate a JSON file that creates an AMI: 193 | 194 | ```bash 195 | packer validate cool-ubuntu-aws-ami.json 196 | ``` 197 | 198 | - Build the AMI with Packer and a JSON file: 199 | ```bash 200 | packer build cool-ubuntu-aws-ami.json 201 | ``` 202 | 203 | ## Usage :dizzy: 204 | 205 | All projects are really well commented and most of them have specifications and remarks for their purpose and I/O.
206 | I will be uploading most of the files, and try to keep it as clean as possible.
207 | 208 | ## Special thanks :gift: 209 | 210 | - Thanks to all contributors of the great OpenSource projects that I am using.
211 | 212 | ## Author :musical_keyboard: 213 | 214 | ### Santiago Garcia Arango 215 | 216 | 217 | 218 | 221 | 224 | 225 |
219 |

Senior DevOps Engineer passionate about advanced cloud-based solutions and deployments in AWS. I am convinced that today's greatest challenges must be solved by people that love what they do.

220 |
222 |

223 |
226 | -------------------------------------------------------------------------------- /assets/img/santi_terraform.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/san99tiago/terraform-playground/4f39c1893bf1bba348216a4ce79657f57a59da6f/assets/img/santi_terraform.jpg -------------------------------------------------------------------------------- /assets/img/terraform_gif.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/san99tiago/terraform-playground/4f39c1893bf1bba348216a4ce79657f57a59da6f/assets/img/terraform_gif.gif -------------------------------------------------------------------------------- /ex00_terraform_intro/.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 = "3.75.1" 6 | constraints = "~> 3.0" 7 | hashes = [ 8 | "h1:++H0a4igODgreQL3SJuRz71JZkC69rl41R8xLYM894o=", 9 | "h1:OuaWibxL7IoGHmX6xuhO2XvYJcr+DJNr9pnVjaUiMrw=", 10 | "zh:11c2ee541ca1da923356c9225575ba294523d7b6af82d6171c912470ef0f90cd", 11 | "zh:19fe975993664252b4a2ff1079546f2b186b01d1a025a94a4f15c37e023806c5", 12 | "zh:442e7fc145b2debebe9279b283d07f5f736dc1776c2e5b1702728a6eb03789d0", 13 | "zh:7a77991b204ae2c16ac29a32226135d5fdbda40c8dafa77c5adf5439a346be77", 14 | "zh:89a257933181c15293c15a858fbfe7252129cc57cc2ec05b6c0b595d1bfe9d38", 15 | "zh:b1813ea5b6b0fd88ea85b1b21b8e4119566d1bc34feca297b4fb39d0536893cb", 16 | "zh:c519f3292ae431bd2381f88a95bd37c52f7a56d91feef88511e929344c180549", 17 | "zh:d3dbe88b661c073c174f04f73adc2720372143bdfa12f4fe8f411332e64662cf", 18 | "zh:e92a27e3c7295b031b5d62dd9428966c96e3157fc768b3d848a9ac60d1661c8e", 19 | "zh:ecd664c0d664fcf2d8a89a01462cb00bcae37da200305aef2de1b8fe185c9cd8", 20 | "zh:ed6ce1f9fa96aa28dd65842f852abed25f919d20b5cf53d26cec5b3f4d845725", 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /ex00_terraform_intro/README.md: -------------------------------------------------------------------------------- 1 | # EXAMPLE 00 TERRAFORM 2 | 3 | ## What we will be doing... 4 | 5 | 1. Configuring Terraform settings inside the `main.tf` file. 6 | 2. Configuring AWS provider in the `main.tf` file. 7 | 3. Creating a really simple AWS resource (in this case an empty VPC called `super_simple_vpc`). 8 | 4. Using the `terraform.tfvars.json` and `variables.tf` files to configure and pass variables to the `main.tf`. 9 | 5. Creating an `outputs.tf` file that contains the VPC ID. 10 | 6. Executing some Terraform commands to understand its behavior. 11 | 12 | 13 | ## Before running this example... 14 | 15 | Remember to add the credentials to the environment variables via an IAM role or user and the specific AWS configuration variables. 16 | 17 | In powershell we can run: 18 | 19 | ```bash 20 | $env:AWS_ACCESS_KEY_ID="" 21 | $env:AWS_SECRET_ACCESS_KEY="" 22 | $env:AWS_ACCOUNT_ID="" 23 | ``` 24 | 25 | In Linux we can execute: 26 | 27 | ```bash 28 | export AWS_ACCESS_KEY_ID="" 29 | export AWS_SECRET_ACCESS_KEY="" 30 | export AWS_ACCOUNT_ID="" 31 | ``` 32 | 33 |
34 | 35 | ## Commands to run 36 | 37 | In this example we will be using the following commands: 38 | 39 | ```bash 40 | terraform init 41 | ``` 42 | 43 | ```bash 44 | terraform plan 45 | ``` 46 | 47 | ```bash 48 | terraform apply 49 | ``` 50 | 51 | ```bash 52 | terraform state help 53 | ``` 54 | 55 | ```bash 56 | terraform state list 57 | ``` 58 | 59 | ```bash 60 | terraform state show aws_vpc.super_simple_vpc 61 | ``` 62 | 63 | ```bash 64 | terraform destroy 65 | ``` 66 | -------------------------------------------------------------------------------- /ex00_terraform_intro/main.tf: -------------------------------------------------------------------------------- 1 | ## DEPLOY AN EMPTY VPC 2 | ## Santiago Garcia Arango 3 | 4 | # Terraform settings: 5 | terraform { 6 | required_version = ">= 1.1.9" 7 | required_providers { 8 | aws = { 9 | source = "hashicorp/aws" 10 | version = "~> 3.0" 11 | } 12 | } 13 | } 14 | 15 | # Configure the AWS Provider 16 | provider "aws" { 17 | region = "us-east-1" 18 | } 19 | 20 | # Create a really simple VPC 21 | resource "aws_vpc" "super_simple_vpc" { 22 | cidr_block = "10.0.0.0/16" 23 | instance_tenancy = "default" 24 | enable_dns_support = "true" 25 | 26 | tags = var.vpc_tags 27 | } 28 | -------------------------------------------------------------------------------- /ex00_terraform_intro/outputs.tf: -------------------------------------------------------------------------------- 1 | output "vpc_id" { 2 | description = "ID of the cool VPC" 3 | value = try(aws_vpc.super_simple_vpc.id, "") 4 | } -------------------------------------------------------------------------------- /ex00_terraform_intro/terraform.tfvars.json: -------------------------------------------------------------------------------- 1 | { 2 | "vpc_tags": { 3 | "Name": "super_simple_vpc", 4 | "Environment": "dev", 5 | "Owner": "Santiago Garcia Arango" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /ex00_terraform_intro/variables.tf: -------------------------------------------------------------------------------- 1 | variable "vpc_tags" { 2 | type = map(string) 3 | description = "Tags for the VPC" 4 | } 5 | -------------------------------------------------------------------------------- /ex01_packer_aws_ami/README.md: -------------------------------------------------------------------------------- 1 | # EXAMPLE 01 PACKER 2 | 3 | ## What we will be doing... 4 | 5 | 1. Configuring Packer to create a custom AWS Amazon Machine Image (AMI). 6 | 2. Understanding that the `cool-ubuntu-aws-ami.json` file contains the necessary Packer configurations for the AMI. 7 | 3. Implementing the `install-docker.sh` file to show how to run commands on our custom AMIs. 8 | 4. Multiple Packer commands to create the custom AMI. 9 | 10 | ## Before running this example... 11 | 12 | Remember to add the credentials to the environment variables via an IAM role or user and the specific AWS configuration variables. 13 | 14 | In powershell we can run: 15 | 16 | ```bash 17 | $env:AWS_ACCESS_KEY_ID="" 18 | $env:AWS_SECRET_ACCESS_KEY="" 19 | $env:AWS_ACCOUNT_ID="" 20 | ``` 21 | 22 | In Linux we can execute: 23 | 24 | ```bash 25 | export AWS_ACCESS_KEY_ID="" 26 | export AWS_SECRET_ACCESS_KEY="" 27 | export AWS_ACCOUNT_ID="" 28 | ``` 29 | 30 |
31 | 32 | ## Commands to run 33 | 34 | In this example we will be using the following commands: 35 | 36 | ```bash 37 | packer validate cool-ubuntu-aws-ami.json 38 | ``` 39 | 40 | ```bash 41 | packer build cool-ubuntu-aws-ami.json 42 | ``` 43 | 44 | > At the end, remember to deregister the AMI and its associated snapshot to reduce costs. 45 | -------------------------------------------------------------------------------- /ex01_packer_aws_ami/cool-ubuntu-aws-ami.json: -------------------------------------------------------------------------------- 1 | { 2 | "variables": { 3 | "aws_account_id": "{{env `AWS_ACCOUNT_ID`}}", 4 | "source_ami": "ami-04505e74c0741db8d", 5 | "aws_instance_type": "t2.micro", 6 | "owner_name": "Santiago Garcia Arango", 7 | "ami_name": "packer-cool-ubuntu-aws-ami" 8 | }, 9 | "builders": [ 10 | { 11 | "type": "amazon-ebs", 12 | "access_key": "{{user `aws_access_key`}}", 13 | "secret_key": "{{user `aws_secret_key`}}", 14 | "region": "us-east-1", 15 | "source_ami": "{{user `source_ami`}}", 16 | "source_ami_filter": { 17 | "most_recent": true 18 | }, 19 | "instance_type": "{{user `aws_instance_type`}}", 20 | "ssh_username": "ubuntu", 21 | "ami_name": "{{user `ami_name`}}-{{timestamp}}", 22 | "ami_description": "My cool Ubuntu personalized AMI via Packer", 23 | "tags": { 24 | "Name": "{{user `ami_name`}}-{{timestamp}}", 25 | "owner": "{{user `owner_name`}}" 26 | } 27 | } 28 | ], 29 | "provisioners": [ 30 | { 31 | "type": "shell", 32 | "pause_before": "5s", 33 | "expect_disconnect": false, 34 | "script": "./scripts/install-docker.sh" 35 | } 36 | ] 37 | } 38 | -------------------------------------------------------------------------------- /ex01_packer_aws_ami/scripts/install-docker.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -x 3 | 4 | echo "----- INITIALIZING CUSTOM AMI CREATION -----" 5 | sudo apt-get update 6 | 7 | sudo apt-get -y install apt-transport-https ca-certificates curl gnupg software-properties-common 8 | 9 | curl -fsSL https://download.docker.com/linux/$(. /etc/os-release; echo "$ID")/gpg | sudo apt-key add - 10 | 11 | sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" 12 | 13 | sudo apt-get update 14 | 15 | sudo apt-get -y install docker-ce -------------------------------------------------------------------------------- /ex02_terraform_basics/.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 = "3.32.0" 6 | hashes = [ 7 | "h1:aY98OcgyLZJVEoqWB8tro023Fx3khJUWQOxwAfd94pQ=", 8 | "h1:l8jJYQ4bPEbNwZUoHYmeR1woajPzJSX5hPCLWuRVFwc=", 9 | "zh:04e4f700c21b1f58e7603638160bd5ad3b85519c35dc75bada3e52b164d06d3e", 10 | "zh:09f2338404d4b2d4dcb29781ac59a6955d935745e896d4ee661d83cac8d7c677", 11 | "zh:16bdf96d8139268766921d5b891b865f67936190dc302283ba50b94e42510ec5", 12 | "zh:1f0eb671390ee41ddf22faf22d00da636e57164214a37c77f7d3fb1f19ea9cce", 13 | "zh:3703b0ba118887cb558085f4b7e732e4e374f455221fcf724bada6f71bd25d55", 14 | "zh:a344b8b1d0c541abcfc3a5bd22aa28d1a07aff416db753d53219158a86e956cc", 15 | "zh:a4798f3bf4ecbdfcd2ea72061e54053423a47f48812749b2cc7dc8dcf8a11eb4", 16 | "zh:aeb5c18afe26388748289f2a3819c7c9210cb669efe01b3e28bf542c51c83bd7", 17 | "zh:b0a3f5940f76dbd3ea9699f98f9cabc443c210c06f30caeb792e5843b7550cc1", 18 | "zh:baa2854e3fbf3df9653a5e6a0f1093a018dad39312346426f4bcefc2ebfd74cc", 19 | "zh:e305b3d227f2013ddd7cf22f2cfa4603a55187c8eddd07f980350a828b67ce49", 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /ex02_terraform_basics/README.md: -------------------------------------------------------------------------------- 1 | # USAGE OF EX02 2 | 3 | ```bash 4 | terraform init 5 | terraform apply --var-file dev.tfvars.json 6 | ``` 7 | -------------------------------------------------------------------------------- /ex02_terraform_basics/dev.tfvars.json: -------------------------------------------------------------------------------- 1 | { 2 | "ami_id": "ami-0261380b551b43297", 3 | "instance_type": "t2.micro", 4 | "tags": { 5 | "Name": "terraform_test_1", 6 | "Environment": "dev" 7 | }, 8 | "sg_name": "my_terraform_sg", 9 | "ingress_rules": [ 10 | { 11 | "from_port": "22", 12 | "to_port": "22", 13 | "protocol": "tcp", 14 | "cidr_blocks": ["0.0.0.0/0"] 15 | }, 16 | { 17 | "from_port": "80", 18 | "to_port": "80", 19 | "protocol": "tcp", 20 | "cidr_blocks": ["0.0.0.0/0"] 21 | } 22 | 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /ex02_terraform_basics/main.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = "us-east-1" 3 | } 4 | 5 | resource "aws_instance" "this" { 6 | ami = var.ami_id 7 | instance_type = var.instance_type 8 | tags = var.tags 9 | security_groups = [aws_security_group.tcp_ssh_connections.name] 10 | } 11 | 12 | resource "aws_security_group" "tcp_ssh_connections" { 13 | name = var.sg_name 14 | description = "Allow TCP and SSH connections." 15 | 16 | dynamic "ingress" { 17 | for_each = var.ingress_rules 18 | content { 19 | description = "SSH ingress rule" 20 | from_port = ingress.value.from_port 21 | to_port = ingress.value.to_port 22 | protocol = ingress.value.protocol 23 | cidr_blocks = ingress.value.cidr_blocks 24 | } 25 | } 26 | 27 | egress { 28 | from_port = 0 29 | to_port = 0 30 | protocol = "-1" 31 | cidr_blocks = ["0.0.0.0/0"] 32 | } 33 | 34 | tags = { 35 | Name = "allow_tcp_and_ssh" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /ex02_terraform_basics/output.tf: -------------------------------------------------------------------------------- 1 | output "instance_ip" { 2 | value = aws_instance.this.*.public_ip 3 | } 4 | -------------------------------------------------------------------------------- /ex02_terraform_basics/variables.tf: -------------------------------------------------------------------------------- 1 | variable "ami_id" { 2 | type = string 3 | description = "The id of the machine image (AMI) to use for the server." 4 | } 5 | 6 | variable "instance_type" { 7 | type = string 8 | description = "Type of the EC2 instace to create." 9 | default = "t2.micro" 10 | } 11 | 12 | variable "tags" { 13 | type = map(string) 14 | description = "Tags for the EC2 instance." 15 | } 16 | 17 | variable "sg_name" { 18 | type = string 19 | description = "Name for the security group." 20 | } 21 | 22 | variable "ingress_rules" { 23 | type = any 24 | description = "Rules for the security group." 25 | } 26 | -------------------------------------------------------------------------------- /ex03_terraform_backend/.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 = "3.32.0" 6 | hashes = [ 7 | "h1:aY98OcgyLZJVEoqWB8tro023Fx3khJUWQOxwAfd94pQ=", 8 | "zh:04e4f700c21b1f58e7603638160bd5ad3b85519c35dc75bada3e52b164d06d3e", 9 | "zh:09f2338404d4b2d4dcb29781ac59a6955d935745e896d4ee661d83cac8d7c677", 10 | "zh:16bdf96d8139268766921d5b891b865f67936190dc302283ba50b94e42510ec5", 11 | "zh:1f0eb671390ee41ddf22faf22d00da636e57164214a37c77f7d3fb1f19ea9cce", 12 | "zh:3703b0ba118887cb558085f4b7e732e4e374f455221fcf724bada6f71bd25d55", 13 | "zh:a344b8b1d0c541abcfc3a5bd22aa28d1a07aff416db753d53219158a86e956cc", 14 | "zh:a4798f3bf4ecbdfcd2ea72061e54053423a47f48812749b2cc7dc8dcf8a11eb4", 15 | "zh:aeb5c18afe26388748289f2a3819c7c9210cb669efe01b3e28bf542c51c83bd7", 16 | "zh:b0a3f5940f76dbd3ea9699f98f9cabc443c210c06f30caeb792e5843b7550cc1", 17 | "zh:baa2854e3fbf3df9653a5e6a0f1093a018dad39312346426f4bcefc2ebfd74cc", 18 | "zh:e305b3d227f2013ddd7cf22f2cfa4603a55187c8eddd07f980350a828b67ce49", 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /ex03_terraform_backend/backend.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | backend "s3" { 3 | bucket = "my-terraform-backend-ex03" 4 | key = "terraform/dev" 5 | region = "us-east-1" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /ex03_terraform_backend/main.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = "us-east-1" 3 | } 4 | 5 | resource "aws_s3_bucket" "terraform-ex03-bucket" { 6 | bucket = var.bucket_name 7 | acl = var.acl 8 | tags = var.tags 9 | } 10 | -------------------------------------------------------------------------------- /ex03_terraform_backend/variables.tf: -------------------------------------------------------------------------------- 1 | variable "bucket_name" { 2 | type = string 3 | description = "Name for the AWS-bucket." 4 | default = "my-terraform-backend-ex03" 5 | } 6 | 7 | variable "acl" { 8 | type = string 9 | description = "AWS Network Access Control List security." 10 | default = "private" 11 | } 12 | 13 | variable "tags" { 14 | type = map(string) 15 | default = { 16 | Environment = "dev", 17 | CreatedBy = "terraform" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /ex03_terraform_backend_01_create_bucket/.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 = "3.32.0" 6 | hashes = [ 7 | "h1:aY98OcgyLZJVEoqWB8tro023Fx3khJUWQOxwAfd94pQ=", 8 | "zh:04e4f700c21b1f58e7603638160bd5ad3b85519c35dc75bada3e52b164d06d3e", 9 | "zh:09f2338404d4b2d4dcb29781ac59a6955d935745e896d4ee661d83cac8d7c677", 10 | "zh:16bdf96d8139268766921d5b891b865f67936190dc302283ba50b94e42510ec5", 11 | "zh:1f0eb671390ee41ddf22faf22d00da636e57164214a37c77f7d3fb1f19ea9cce", 12 | "zh:3703b0ba118887cb558085f4b7e732e4e374f455221fcf724bada6f71bd25d55", 13 | "zh:a344b8b1d0c541abcfc3a5bd22aa28d1a07aff416db753d53219158a86e956cc", 14 | "zh:a4798f3bf4ecbdfcd2ea72061e54053423a47f48812749b2cc7dc8dcf8a11eb4", 15 | "zh:aeb5c18afe26388748289f2a3819c7c9210cb669efe01b3e28bf542c51c83bd7", 16 | "zh:b0a3f5940f76dbd3ea9699f98f9cabc443c210c06f30caeb792e5843b7550cc1", 17 | "zh:baa2854e3fbf3df9653a5e6a0f1093a018dad39312346426f4bcefc2ebfd74cc", 18 | "zh:e305b3d227f2013ddd7cf22f2cfa4603a55187c8eddd07f980350a828b67ce49", 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /ex03_terraform_backend_01_create_bucket/README.md: -------------------------------------------------------------------------------- 1 | # EXAMPLE 03 TERRAFORM BACKEND PART 01 2 | 3 | ## What we will be doing... 4 | 5 | 1. Creating a bucket that will store Terraform State (Terraform Backend) for the next part. 6 | 7 | ## Before running this example... 8 | 9 | Remember to add the credentials to the environment variables via an IAM role or user and the specific AWS configuration variables. 10 | 11 | In powershell we can run: 12 | 13 | ```bash 14 | $env:AWS_ACCESS_KEY_ID="" 15 | $env:AWS_SECRET_ACCESS_KEY="" 16 | $env:AWS_ACCOUNT_ID="" 17 | ``` 18 | 19 | In Linux we can execute: 20 | 21 | ```bash 22 | export AWS_ACCESS_KEY_ID="" 23 | export AWS_SECRET_ACCESS_KEY="" 24 | export AWS_ACCOUNT_ID="" 25 | ``` 26 | 27 |
28 | 29 | ## Important commands... 30 | 31 | In this example we will be using the following commands: 32 | 33 | ```bash 34 | terraform init 35 | ``` 36 | 37 | ```bash 38 | terraform plan 39 | ``` 40 | 41 | ```bash 42 | terraform apply 43 | ``` 44 | 45 | ```bash 46 | terraform destroy 47 | ``` 48 | -------------------------------------------------------------------------------- /ex03_terraform_backend_01_create_bucket/main.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = "us-east-1" 3 | } 4 | 5 | # ---------- THIS FIRST PART IS DEDICATED FOR THE TERRAFORM BACKEND ---------- 6 | resource "aws_s3_bucket" "my_backend_bucket" { 7 | bucket = var.bucket_name 8 | tags = var.tags 9 | } 10 | 11 | resource "aws_s3_bucket_public_access_block" "my_backend_bucket_block_public_access_block" { 12 | bucket = aws_s3_bucket.my_backend_bucket.id 13 | 14 | block_public_acls = true 15 | block_public_policy = true 16 | ignore_public_acls = true 17 | restrict_public_buckets = true 18 | } 19 | -------------------------------------------------------------------------------- /ex03_terraform_backend_01_create_bucket/variables.tf: -------------------------------------------------------------------------------- 1 | variable "bucket_name" { 2 | type = string 3 | description = "Name for the AWS bucket that has the Terraform Backend." 4 | # WARNING: Remember that you have to use an unique bucket name in the world 5 | default = "my-terraform-backend-ex03" 6 | } 7 | 8 | variable "tags" { 9 | type = map(string) 10 | 11 | default = { 12 | Environment = "dev", 13 | Owner = "Santiago Garcia Arango", 14 | Source = "terraform-playground" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /ex03_terraform_backend_02_create_resources/.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 = "3.32.0" 6 | hashes = [ 7 | "h1:aY98OcgyLZJVEoqWB8tro023Fx3khJUWQOxwAfd94pQ=", 8 | "zh:04e4f700c21b1f58e7603638160bd5ad3b85519c35dc75bada3e52b164d06d3e", 9 | "zh:09f2338404d4b2d4dcb29781ac59a6955d935745e896d4ee661d83cac8d7c677", 10 | "zh:16bdf96d8139268766921d5b891b865f67936190dc302283ba50b94e42510ec5", 11 | "zh:1f0eb671390ee41ddf22faf22d00da636e57164214a37c77f7d3fb1f19ea9cce", 12 | "zh:3703b0ba118887cb558085f4b7e732e4e374f455221fcf724bada6f71bd25d55", 13 | "zh:a344b8b1d0c541abcfc3a5bd22aa28d1a07aff416db753d53219158a86e956cc", 14 | "zh:a4798f3bf4ecbdfcd2ea72061e54053423a47f48812749b2cc7dc8dcf8a11eb4", 15 | "zh:aeb5c18afe26388748289f2a3819c7c9210cb669efe01b3e28bf542c51c83bd7", 16 | "zh:b0a3f5940f76dbd3ea9699f98f9cabc443c210c06f30caeb792e5843b7550cc1", 17 | "zh:baa2854e3fbf3df9653a5e6a0f1093a018dad39312346426f4bcefc2ebfd74cc", 18 | "zh:e305b3d227f2013ddd7cf22f2cfa4603a55187c8eddd07f980350a828b67ce49", 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /ex03_terraform_backend_02_create_resources/README.md: -------------------------------------------------------------------------------- 1 | # EXAMPLE 03 TERRAFORM BACKEND PART 02 2 | 3 | ## What we will be doing... 4 | 5 | 1. Creating a couple of resources and storing the state inside an specific bucket for the "Terraform Backend". 6 | 2. Validate that the state is stored remotely in the S3 bucket at `dev/state` after executing the terraform commands. 7 | 8 | ## Before running this example... 9 | 10 | Remember to add the credentials to the environment variables via an IAM role or user and the specific AWS configuration variables. 11 | 12 | In powershell we can run: 13 | 14 | ```bash 15 | $env:AWS_ACCESS_KEY_ID="" 16 | $env:AWS_SECRET_ACCESS_KEY="" 17 | $env:AWS_ACCOUNT_ID="" 18 | ``` 19 | 20 | In Linux we can execute: 21 | 22 | ```bash 23 | export AWS_ACCESS_KEY_ID="" 24 | export AWS_SECRET_ACCESS_KEY="" 25 | export AWS_ACCOUNT_ID="" 26 | ``` 27 | 28 |
29 | 30 | ## Important commands... 31 | 32 | In this example we will be using the following commands: 33 | 34 | ```bash 35 | terraform init 36 | ``` 37 | 38 | ```bash 39 | terraform plan 40 | ``` 41 | 42 | ```bash 43 | terraform apply 44 | ``` 45 | 46 | ```bash 47 | terraform destroy 48 | ``` 49 | -------------------------------------------------------------------------------- /ex03_terraform_backend_02_create_resources/backend.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | backend "s3" { 3 | # COMMENTED OUT: This is the default backend configuration 4 | bucket = "santisantisanti" # Manually created 5 | key = "terraform/dev/ex03_state.json" 6 | region = "us-east-1" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /ex03_terraform_backend_02_create_resources/main.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = "us-east-1" 3 | } 4 | 5 | # ---------- THIS SECOND PART IS AFTER BACKEND BUCKET IS CREATED ---------- 6 | 7 | resource "aws_vpc" "my_vpc" { 8 | cidr_block = "10.0.0.0/16" 9 | 10 | tags = merge( 11 | var.base_tags, 12 | { 13 | Name = "custom-vpc-ex03" 14 | } 15 | ) 16 | } 17 | 18 | resource "aws_security_group" "my_sg_allow_tls" { 19 | name = "allow_tls_sg" 20 | description = "Allow TLS inbound traffic from anywhere" 21 | vpc_id = aws_vpc.my_vpc.id 22 | 23 | ingress { 24 | description = "TLS from VPC" 25 | from_port = 443 26 | to_port = 443 27 | protocol = "tcp" 28 | cidr_blocks = ["0.0.0.0/0"] 29 | ipv6_cidr_blocks = ["::/0"] 30 | } 31 | 32 | egress { 33 | from_port = 0 34 | to_port = 0 35 | protocol = "-1" 36 | cidr_blocks = ["0.0.0.0/0"] 37 | ipv6_cidr_blocks = ["::/0"] 38 | } 39 | 40 | tags = merge( 41 | var.base_tags, 42 | { 43 | Name = "allow_tls_sg" 44 | } 45 | ) 46 | } -------------------------------------------------------------------------------- /ex03_terraform_backend_02_create_resources/variables.tf: -------------------------------------------------------------------------------- 1 | variable "base_tags" { 2 | type = map(string) 3 | 4 | default = { 5 | Environment = "dev", 6 | Owner = "Santiago Garcia Arango", 7 | Source = "terraform-playground" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /ex04_terraform_vpc_with_subnets_and_ec2/.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 = "3.33.0" 6 | hashes = [ 7 | "h1:dfszrcpjXjaZN3XsCz7TWhucZkNxZ6AVyoL890K+RdI=", 8 | "zh:0e89b10323a59de9dd6f286423cc172cb1733683d654c886493c3bd4e43e6290", 9 | "zh:288df55f0f4fac1e920cfa61616ac42a4e4414bd7a637902db03d0c7101f14ca", 10 | "zh:303c9136c5bf97e6c1deda6e27f0d0931fe0eaaab547bf219b996623fb0ad522", 11 | "zh:457a5da9f323e2781942df534153d000ea81727798ee0771177009d84b04aad7", 12 | "zh:857fa3e29cc25ace76556a5edfded41628a3380cebf457e627576a83084852f8", 13 | "zh:85e1eb383372f834630fac7b02ec9ae1e33d24d61cf5a7d832583a16e6b5add4", 14 | "zh:9dd01eb05ac73146ac5f25421b7683fe4bffec23e408162887e1265f9bfe8462", 15 | "zh:b1561e1335754ec93a54f45c18dc1cab70f38bc08adf244d793791134f5641ef", 16 | "zh:bb96f57b80e3d94ee4bc05a5450fdd796424272b46cfc67ff9d094d5316c5fac", 17 | "zh:e4ce241d8b5dd1124dc0f1da6c0840ab777de8717dac6e76afbbad9883f5ce34", 18 | "zh:f2b292e813844d6d611db89017fc420ac05f2e3b25324e3c893481d375e23396", 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /ex04_terraform_vpc_with_subnets_and_ec2/README.md: -------------------------------------------------------------------------------- 1 | # EXAMPLE 04 TERRAFORM 2 | 3 | ## What we will be doing... 4 | 5 | 1. Creating a VPC. 6 | 2. Creating an Internet Gateway. 7 | 3. Creating a custom Route Table. 8 | 4. Creating a Subnet for the VPC. 9 | 5. Associating a Subnet with the Route Table. 10 | 6. Creating a Security Group to allow ports 22, 80, 443 and 5000. 11 | 7. Creating a Network Interface with an IP in the Subnet that was created in 12 | step number 4. 13 | 8. Assigning an Elastic IP to the Network Interface created in step number 7. 14 | 9. Creating an Ubuntu server and installing apache2. 15 | 16 | ## Before running this example... 17 | 18 | Remember to add the credentials to the environment variables via an IAM role or user and the specific AWS configuration variables. 19 | 20 | In powershell we can run: 21 | 22 | ```bash 23 | $env:AWS_ACCESS_KEY_ID="" 24 | $env:AWS_SECRET_ACCESS_KEY="" 25 | $env:AWS_ACCOUNT_ID="" 26 | ``` 27 | 28 | In Linux we can execute: 29 | 30 | ```bash 31 | export AWS_ACCESS_KEY_ID="" 32 | export AWS_SECRET_ACCESS_KEY="" 33 | export AWS_ACCOUNT_ID="" 34 | ``` 35 | 36 |
37 | 38 | ## Important commands... 39 | 40 | In this example we will be using the following commands: 41 | 42 | ```bash 43 | terraform init 44 | ``` 45 | 46 | ```bash 47 | terraform plan --var-file dev.tfvars.json 48 | ``` 49 | 50 | ```bash 51 | terraform apply --var-file dev.tfvars.json --auto-approve 52 | ``` 53 | 54 | ```bash 55 | terraform destroy --var-file dev.tfvars.json --auto-approve 56 | ``` 57 | -------------------------------------------------------------------------------- /ex04_terraform_vpc_with_subnets_and_ec2/dev.tfvars.json: -------------------------------------------------------------------------------- 1 | { 2 | "aws_region": "us-east-1", 3 | 4 | "aws_availability_zone": "us-east-1a", 5 | 6 | "vpc_cidr_block": "10.0.0.0/16", 7 | "vpc_tags": { 8 | "Name": "terraform-dev-vpc-4", 9 | "Environment": "dev" 10 | }, 11 | "vpc_instance_tenancy": "default", 12 | 13 | "gw_tags": { 14 | "Name": "terraform-dev-gw-4", 15 | "Environment": "dev" 16 | }, 17 | 18 | "rt_tags": { 19 | "Name": "terraform-dev-rt-4", 20 | "Environment": "dev" 21 | }, 22 | 23 | "vpc_subnet_cidr_block": "10.0.1.0/24", 24 | "vpc_subnet_tags": { 25 | "Name": "terraform-dev-subnet-4-A", 26 | "Environment": "dev" 27 | }, 28 | 29 | "sg_name": "terraform-dev-sg-4", 30 | "sg_tags": { 31 | "Name": "terraform-dev-sg-4", 32 | "Environment": "dev" 33 | }, 34 | "sg_ingress_rules": [ 35 | { 36 | "from_port": "22", 37 | "to_port": "22", 38 | "protocol": "tcp", 39 | "cidr_blocks": ["0.0.0.0/0"] 40 | }, 41 | { 42 | "from_port": "80", 43 | "to_port": "80", 44 | "protocol": "tcp", 45 | "cidr_blocks": ["0.0.0.0/0"] 46 | }, 47 | { 48 | "from_port": "443", 49 | "to_port": "443", 50 | "protocol": "tcp", 51 | "cidr_blocks": ["0.0.0.0/0"] 52 | }, 53 | { 54 | "from_port": "5000", 55 | "to_port": "5000", 56 | "protocol": "tcp", 57 | "cidr_blocks": ["0.0.0.0/0"] 58 | } 59 | ], 60 | "sg_egress_rules": [ 61 | { 62 | "from_port": "22", 63 | "to_port": "22", 64 | "protocol": "tcp", 65 | "cidr_blocks": ["0.0.0.0/0"] 66 | }, 67 | { 68 | "from_port": "80", 69 | "to_port": "80", 70 | "protocol": "tcp", 71 | "cidr_blocks": ["0.0.0.0/0"] 72 | }, 73 | { 74 | "from_port": "443", 75 | "to_port": "443", 76 | "protocol": "tcp", 77 | "cidr_blocks": ["0.0.0.0/0"] 78 | }, 79 | { 80 | "from_port": "5000", 81 | "to_port": "5000", 82 | "protocol": "tcp", 83 | "cidr_blocks": ["0.0.0.0/0"] 84 | } 85 | ], 86 | 87 | "network_interface_private_ips": "10.0.1.50", 88 | 89 | "instance_ami_id": "ami-042e8287309f5df03", 90 | "instance_type": "t2.micro", 91 | "instance_tags": { 92 | "Name": "terraform-dev-instance-4", 93 | "Environment": "dev" 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /ex04_terraform_vpc_with_subnets_and_ec2/main.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = var.aws_region 3 | } 4 | 5 | resource "aws_vpc" "my-terraform-vpc" { 6 | cidr_block = var.vpc_cidr_block 7 | instance_tenancy = var.vpc_instance_tenancy 8 | tags = var.vpc_tags 9 | } 10 | 11 | resource "aws_internet_gateway" "my-terraform-internet-gw" { 12 | vpc_id = aws_vpc.my-terraform-vpc.id 13 | tags = var.gw_tags 14 | } 15 | 16 | resource "aws_route_table" "my-terraform-rt" { 17 | vpc_id = aws_vpc.my-terraform-vpc.id 18 | tags = var.rt_tags 19 | route { 20 | cidr_block = "0.0.0.0/0" 21 | gateway_id = aws_internet_gateway.my-terraform-internet-gw.id 22 | } 23 | route { 24 | ipv6_cidr_block = "::/0" 25 | gateway_id = aws_internet_gateway.my-terraform-internet-gw.id 26 | } 27 | } 28 | 29 | resource "aws_subnet" "my-terraform-subnet-A" { 30 | vpc_id = aws_vpc.my-terraform-vpc.id 31 | cidr_block = var.vpc_subnet_cidr_block 32 | availability_zone = var.aws_availability_zone 33 | tags = var.vpc_subnet_tags 34 | } 35 | 36 | resource "aws_route_table_association" "my-terraform-rt-association" { 37 | subnet_id = aws_subnet.my-terraform-subnet-A.id 38 | route_table_id = aws_route_table.my-terraform-rt.id 39 | } 40 | 41 | resource "aws_security_group" "my-terraform-security-group" { 42 | name = var.sg_name 43 | description = "Allow custom TCP and SSH connections." 44 | vpc_id = aws_vpc.my-terraform-vpc.id 45 | dynamic "ingress" { 46 | for_each = var.sg_ingress_rules 47 | content { 48 | description = "SG ingress rule" 49 | from_port = ingress.value.from_port 50 | to_port = ingress.value.to_port 51 | protocol = ingress.value.protocol 52 | cidr_blocks = ingress.value.cidr_blocks 53 | } 54 | } 55 | dynamic "egress" { 56 | for_each = var.sg_egress_rules 57 | content { 58 | description = "SG egress rule" 59 | from_port = egress.value.from_port 60 | to_port = egress.value.to_port 61 | protocol = egress.value.protocol 62 | cidr_blocks = egress.value.cidr_blocks 63 | } 64 | } 65 | tags = var.sg_tags 66 | } 67 | 68 | resource "aws_network_interface" "my-terraform-network-interface" { 69 | subnet_id = aws_subnet.my-terraform-subnet-A.id 70 | private_ips = [var.network_interface_private_ips] 71 | security_groups = [aws_security_group.my-terraform-security-group.id] 72 | } 73 | 74 | resource "aws_eip" "my-terraform-eip" { 75 | vpc = true 76 | network_interface = aws_network_interface.my-terraform-network-interface.id 77 | associate_with_private_ip = var.network_interface_private_ips 78 | depends_on = [aws_internet_gateway.my-terraform-internet-gw] 79 | } 80 | 81 | resource "aws_instance" "my-terraform-instance" { 82 | ami = var.instance_ami_id 83 | instance_type = var.instance_type 84 | availability_zone = var.aws_availability_zone 85 | network_interface { 86 | device_index = 0 87 | network_interface_id = aws_network_interface.my-terraform-network-interface.id 88 | } 89 | user_data = <<-EOF 90 | #!/bin/bash 91 | sudo apt update -y 92 | sudo apt install apache2 -y 93 | sudo systemctl start apache2 94 | sudo bash -c 'echo my first cool web server from IaC > /var/www/html/index.html' 95 | EOF 96 | tags = var.instance_tags 97 | } 98 | -------------------------------------------------------------------------------- /ex04_terraform_vpc_with_subnets_and_ec2/output.tf: -------------------------------------------------------------------------------- 1 | output "server_public_ip" { 2 | value = aws_eip.my-terraform-eip.public_ip 3 | } 4 | 5 | output "server_private_ip" { 6 | value = aws_eip.my-terraform-eip.private_ip 7 | } 8 | -------------------------------------------------------------------------------- /ex04_terraform_vpc_with_subnets_and_ec2/variables.tf: -------------------------------------------------------------------------------- 1 | variable "aws_region" { 2 | type = string 3 | description = "Region for thw AWS deployment." 4 | } 5 | 6 | variable "aws_availability_zone" { 7 | type = string 8 | description = "Availability Zone within selected Region." 9 | } 10 | 11 | variable "vpc_cidr_block" { 12 | type = string 13 | description = "Cidr_block for the VPC." 14 | } 15 | 16 | variable "vpc_instance_tenancy" { 17 | type = string 18 | description = "Instance tenancy for the VPC." 19 | } 20 | 21 | variable "vpc_tags" { 22 | type = map(string) 23 | description = "Tags for the VPC." 24 | } 25 | 26 | variable "gw_tags" { 27 | type = map(string) 28 | description = "Tags for the GateWay." 29 | } 30 | 31 | variable "rt_tags" { 32 | type = map(string) 33 | description = "Tags for the Route Table." 34 | } 35 | 36 | variable "vpc_subnet_cidr_block" { 37 | type = string 38 | description = "Cidr_block for the Subnet for the VPC." 39 | } 40 | 41 | variable "vpc_subnet_tags" { 42 | type = map(string) 43 | description = "Tags of the Subnet for the VPC." 44 | } 45 | 46 | variable "sg_name" { 47 | type = string 48 | description = "Name for the security group." 49 | } 50 | 51 | variable "sg_tags" { 52 | type = map(string) 53 | description = "Tags for the security group." 54 | } 55 | 56 | variable "sg_ingress_rules" { 57 | type = any 58 | description = "Ingress rules for the security group." 59 | } 60 | 61 | variable "sg_egress_rules" { 62 | type = any 63 | description = "Egress rules for the security group." 64 | } 65 | 66 | variable "network_interface_private_ips" { 67 | type = any 68 | description = "Private IPs for the Network Interface." 69 | } 70 | 71 | variable "instance_ami_id" { 72 | type = string 73 | description = "The id of the machine image (AMI) to use for the server." 74 | } 75 | 76 | variable "instance_type" { 77 | type = string 78 | description = "Type of the EC2 instace to create." 79 | default = "t2.micro" 80 | } 81 | 82 | variable "instance_tags" { 83 | type = map(string) 84 | description = "Tags for the EC2 instance." 85 | } 86 | -------------------------------------------------------------------------------- /ex05_terraform_simple_lambda/.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 = "3.44.0" 6 | hashes = [ 7 | "h1:4lZHTWz4LQApWE8ZyWtxGtK2JQBohVJaTiw5AzlWzmA=", 8 | "zh:0680315b29a140e9b7e4f5aeed3f2445abdfab31fc9237f34dcad06de4f410df", 9 | "zh:13811322a205fb4a0ee617f0ae51ec94176befdf569235d0c7064db911f0acc7", 10 | "zh:25e427a1cfcb1d411bc12040cf0684158d094416ecf18889a41196bacc761729", 11 | "zh:40cd6acd24b060823f8d116355d8f844461a11925796b1757eb2ee18abc0bc7c", 12 | "zh:94e2463eef555c388cd27f6e85ad803692d6d80ffa621bdc382ab119001d4de4", 13 | "zh:aadc3bc216b14839e85b463f07b8507920ace5f202a608e4a835df23711c8a0d", 14 | "zh:ab50dc1242af5a8fcdb18cf89beeaf2b2146b51ecfcecdbea033913a5f4c1c14", 15 | "zh:ad48bbf4af66b5d48ca07c5c558d2f5724311db4dd943c1c98a7f3f107e03311", 16 | "zh:ad76796c2145a7aaec1970a5244f5c0a9d200556121e2c5b382f296597b1a03c", 17 | "zh:cf0a2181356598f8a2abfeaf0cdf385bdeea7f2e52821c850a2a08b60c26b9f6", 18 | "zh:f76801af6bc34fe4a5bf1c63fa0204e24b81691049efecd6baa1526593f03935", 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /ex05_terraform_simple_lambda/buckets.tf: -------------------------------------------------------------------------------- 1 | resource "aws_s3_bucket" "mybucket" { 2 | bucket = var.bucketname 3 | acl = "private" 4 | } 5 | -------------------------------------------------------------------------------- /ex05_terraform_simple_lambda/createresources: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/san99tiago/terraform-playground/4f39c1893bf1bba348216a4ce79657f57a59da6f/ex05_terraform_simple_lambda/createresources -------------------------------------------------------------------------------- /ex05_terraform_simple_lambda/index.js: -------------------------------------------------------------------------------- 1 | exports.handler = (event, context, callback) => { 2 | callback(null, "Hello my friends"); 3 | }; 4 | -------------------------------------------------------------------------------- /ex05_terraform_simple_lambda/lambda.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/san99tiago/terraform-playground/4f39c1893bf1bba348216a4ce79657f57a59da6f/ex05_terraform_simple_lambda/lambda.zip -------------------------------------------------------------------------------- /ex05_terraform_simple_lambda/lambdas.tf: -------------------------------------------------------------------------------- 1 | resource "aws_iam_role" "iam_for_lambda_devsecops" { 2 | name = "iam_for_lambda_devsecops" 3 | 4 | assume_role_policy = <Deployed via Terraform by Laura :) " | sudo tee /var/www/html/index.html 117 | EOF 118 | } 119 | 120 | # Crear el Application Load Balancer 121 | resource "aws_lb" "web_lb" { 122 | name = "unique-web-lb-name" 123 | internal = false 124 | load_balancer_type = "application" 125 | security_groups = [aws_security_group.elb_sg.id] 126 | subnets = aws_subnet.public.*.id 127 | enable_deletion_protection = false 128 | 129 | enable_cross_zone_load_balancing = true 130 | enable_http2 = true 131 | } 132 | 133 | # Crear el listener para el ALB 134 | resource "aws_lb_listener" "http" { 135 | load_balancer_arn = aws_lb.web_lb.arn 136 | port = 80 137 | protocol = "HTTP" 138 | 139 | # CAMBIO 4 140 | default_action { 141 | type = "forward" 142 | target_group_arn = aws_lb_target_group.web_tg.arn 143 | } 144 | } 145 | 146 | # Crear el grupo de destino para el ALB 147 | resource "aws_lb_target_group" "web_tg" { 148 | name = "web-tg-1" 149 | port = 80 150 | protocol = "HTTP" 151 | vpc_id = aws_vpc.main.id 152 | 153 | health_check { 154 | interval = 30 155 | timeout = 5 156 | healthy_threshold = 2 157 | unhealthy_threshold = 2 158 | path = "/" 159 | } 160 | } 161 | 162 | # Asociar las instancias EC2 al grupo de destino del ALB 163 | resource "aws_lb_target_group_attachment" "web_instance" { 164 | count = 2 165 | target_group_arn = aws_lb_target_group.web_tg.arn 166 | target_id = aws_instance.web[count.index].id 167 | port = 80 168 | } 169 | -------------------------------------------------------------------------------- /other_examples/alb_to_ec2/output.tf: -------------------------------------------------------------------------------- 1 | output "instance_ips" { 2 | value = aws_instance.web[*].public_ip 3 | } 4 | 5 | output "elb_dns_name" { 6 | value = aws_lb.web_lb.dns_name 7 | } 8 | -------------------------------------------------------------------------------- /other_examples/alb_to_ec2/variables.tf: -------------------------------------------------------------------------------- 1 | variable "aws_region" { 2 | description = "La región de AWS a usar" 3 | type = string 4 | } 5 | 6 | variable "vpc_cidr_block" { 7 | description = "El bloque CIDR de la VPC" 8 | type = string 9 | } 10 | 11 | variable "aws_availability_zones" { 12 | description = "Las zonas de disponibilidad en las que se crearán las subredes" 13 | type = list(string) 14 | default = ["us-east-1a", "us-east-1b"] # Puedes ajustar según tu región 15 | } 16 | 17 | variable "vpc_subnet_cidr" { 18 | description = "CIDR para las subredes" 19 | type = list(string) 20 | default = ["10.0.1.0/24", "10.0.2.0/24"] # Asegúrate de que coincida con las zonas de disponibilidad 21 | } 22 | 23 | 24 | 25 | variable "instance_ami_id" { 26 | description = "ID de la AMI para las instancias EC2" 27 | type = string 28 | } 29 | 30 | variable "instance_type" { 31 | description = "Tipo de instancia EC2" 32 | type = string 33 | } 34 | 35 | variable "elb_tags" { 36 | description = "Etiquetas para el ALB" 37 | type = map(string) 38 | default = {} 39 | } 40 | -------------------------------------------------------------------------------- /other_examples/lambda_python_api/Makefile: -------------------------------------------------------------------------------- 1 | install: 2 | cd lambda-layers && $(MAKE) 3 | 4 | clean: 5 | cd lambda-layers && $(MAKE) clean 6 | -------------------------------------------------------------------------------- /other_examples/lambda_python_api/lambda-layers/Makefile: -------------------------------------------------------------------------------- 1 | install: 2 | cd fastapi && $(MAKE) 3 | 4 | clean: 5 | cd fastapi && $(MAKE) clean 6 | -------------------------------------------------------------------------------- /other_examples/lambda_python_api/lambda-layers/fastapi/Makefile: -------------------------------------------------------------------------------- 1 | install: 2 | [ -d "modules/python" ] || pip install -r requirements.txt -t modules/python/ --platform manylinux2014_x86_64 --python-version 3.12 --implementation cp --only-binary=:all: --upgrade 3 | 4 | clean: 5 | rm -rf modules 6 | -------------------------------------------------------------------------------- /other_examples/lambda_python_api/lambda-layers/fastapi/requirements.txt: -------------------------------------------------------------------------------- 1 | fastapi==0.109.0 2 | mangum==0.17.0 3 | -------------------------------------------------------------------------------- /other_examples/lambda_python_api/src/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/san99tiago/terraform-playground/4f39c1893bf1bba348216a4ce79657f57a59da6f/other_examples/lambda_python_api/src/__init__.py -------------------------------------------------------------------------------- /other_examples/lambda_python_api/src/lambdas/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/san99tiago/terraform-playground/4f39c1893bf1bba348216a4ce79657f57a59da6f/other_examples/lambda_python_api/src/lambdas/__init__.py -------------------------------------------------------------------------------- /other_examples/lambda_python_api/src/lambdas/api/main.py: -------------------------------------------------------------------------------- 1 | import random 2 | import datetime 3 | 4 | # External imports 5 | from fastapi import FastAPI 6 | from mangum import Mangum 7 | import boto3 8 | 9 | 10 | app = FastAPI() 11 | 12 | 13 | NAMES = [ 14 | "Juan", 15 | "Pedro", 16 | "Pablo", 17 | "Maria", 18 | "Ana", 19 | "Lucia", 20 | "Luis", 21 | "Carlos", 22 | "Jose", 23 | "Jorge", 24 | ] 25 | LASTNAMES = [ 26 | "Perez", 27 | "Gonzalez", 28 | "Rodriguez", 29 | "Fernandez", 30 | "Lopez", 31 | "Martinez", 32 | "Sanchez", 33 | "Gomez", 34 | "Diaz", 35 | "Torres", 36 | ] 37 | 38 | # IN MEMORY LIST (DEMO PURPOSES) 39 | ALL_CONTACTS = [] 40 | 41 | # Initialize Dynamodb client 42 | dynamodb_client = boto3.client("dynamodb") 43 | 44 | 45 | @app.get("/") 46 | async def root(): 47 | # Save random contact 48 | contact = random.choice(NAMES) + " " + random.choice(LASTNAMES) 49 | print(f"Created random contact: {contact}") 50 | 51 | # Add contact to our contact list in memory 52 | ALL_CONTACTS.append(contact) 53 | 54 | # # Guardar contacto en DynamoDB 55 | # dynamodb_client.put_item( 56 | # TableName="san99tiago-terraform-dev", 57 | # Item={ 58 | # "LockID": {"S": contact}, 59 | # "DateTime": {"S": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")}, 60 | # "Type": {"S": "Contact"}, 61 | # "Number": {"N": str(random.randint(1, 100))}, 62 | # }, 63 | # ) 64 | 65 | return {"contacts": [contact]} 66 | 67 | 68 | # This is the Lambda Function's entrypoint (handler) 69 | handler = Mangum(app) 70 | -------------------------------------------------------------------------------- /other_examples/lambda_python_api/terraform/backend.tf: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /other_examples/lambda_python_api/terraform/lambda.tf: -------------------------------------------------------------------------------- 1 | data "aws_iam_policy_document" "lambda_trust_policy" { 2 | statement { 3 | effect = "Allow" 4 | actions = ["sts:AssumeRole"] 5 | principals { 6 | type = "Service" 7 | identifiers = ["lambda.amazonaws.com"] 8 | } 9 | } 10 | } 11 | 12 | resource "aws_iam_role" "lambda_role" { 13 | name = "${var.main_resources_name}-role-${var.environment}" 14 | assume_role_policy = data.aws_iam_policy_document.lambda_trust_policy.json 15 | } 16 | 17 | resource "aws_iam_policy" "s3_access" { 18 | name = "s3_access_santi" 19 | path = "/" 20 | description = "My test policy" 21 | 22 | # Terraform's "jsonencode" function converts a 23 | # Terraform expression result to valid JSON syntax. 24 | policy = jsonencode({ 25 | Version = "2012-10-17" 26 | Statement = [ 27 | { 28 | Action = [ 29 | "s3:*", 30 | ] 31 | Effect = "Allow" 32 | Resource = "*" 33 | }, 34 | ] 35 | }) 36 | } 37 | 38 | resource "aws_iam_policy" "dynamodb_santi" { 39 | name = "dynamodb_santi_santi" 40 | path = "/" 41 | description = "My test policy" 42 | 43 | # Terraform's "jsonencode" function converts a 44 | # Terraform expression result to valid JSON syntax. 45 | policy = jsonencode({ 46 | Version = "2012-10-17" 47 | Statement = [ 48 | { 49 | Action = [ 50 | "dynamodb:*", 51 | ] 52 | Effect = "Allow" 53 | Resource = "*" 54 | }, 55 | ] 56 | }) 57 | } 58 | 59 | # Add "AWSLambdaBasicExecutionRole" to the role for the Lambda Function 60 | resource "aws_iam_role_policy_attachment" "lambda_basic_execution_role" { 61 | role = aws_iam_role.lambda_role.name 62 | policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" 63 | } 64 | 65 | resource "aws_iam_role_policy_attachment" "s3_access" { 66 | role = aws_iam_role.lambda_role.name 67 | policy_arn = aws_iam_policy.s3_access.arn 68 | } 69 | 70 | resource "aws_iam_role_policy_attachment" "dynamodb_santi" { 71 | role = aws_iam_role.lambda_role.name 72 | policy_arn = aws_iam_policy.dynamodb_santi.arn 73 | } 74 | 75 | # Create ZIP file for the source code at deployment time 76 | data "archive_file" "lambda_source_package" { 77 | type = "zip" 78 | source_dir = "${local.src_root_path}/lambdas" 79 | output_path = "${local.src_root_path}/lambda_package.zip" 80 | } 81 | 82 | # Lambda Layer Install (Python dependencies) 83 | resource "null_resource" "lambda_layer_install_deps" { 84 | provisioner "local-exec" { 85 | command = "make install" 86 | working_dir = local.root_path 87 | } 88 | 89 | # Enforce to always execute the command 90 | triggers = { 91 | always_run = "${timestamp()}" 92 | } 93 | } 94 | 95 | # Create ZIP file for Lambda Layer (Python dependencies) 96 | data "archive_file" "lambda_layer_package" { 97 | type = "zip" 98 | source_dir = "${local.lambda_layers_root_path}/fastapi/modules" 99 | output_path = "${local.lambda_layers_root_path}/fastapi/modules/lambda_layer_package.zip" 100 | 101 | depends_on = [null_resource.lambda_layer_install_deps] 102 | } 103 | 104 | # Lambda Layer 105 | resource "aws_lambda_layer_version" "lambda_layer" { 106 | filename = "${local.lambda_layers_root_path}/fastapi/modules/lambda_layer_package.zip" 107 | layer_name = "${var.main_resources_name}-layer" 108 | compatible_runtimes = ["python3.12"] 109 | compatible_architectures = ["x86_64"] 110 | source_code_hash = data.archive_file.lambda_layer_package.output_base64sha256 # Enforce re-deploy on changes 111 | 112 | depends_on = [data.archive_file.lambda_layer_package] 113 | 114 | } 115 | 116 | resource "aws_lambda_function" "lambda" { 117 | function_name = "${var.main_resources_name}-${var.environment}" 118 | filename = "${local.src_root_path}/lambda_package.zip" 119 | handler = "api/main.handler" 120 | role = aws_iam_role.lambda_role.arn 121 | runtime = "python3.12" 122 | timeout = 20 123 | architectures = ["x86_64"] 124 | layers = [aws_lambda_layer_version.lambda_layer.arn] 125 | source_code_hash = data.archive_file.lambda_source_package.output_base64sha256 # Enforce re-deploy on changes 126 | 127 | 128 | environment { 129 | variables = { 130 | ENVIRONMENT = var.environment 131 | } 132 | } 133 | 134 | depends_on = [ 135 | data.archive_file.lambda_source_package, 136 | data.archive_file.lambda_layer_package, 137 | ] 138 | 139 | } 140 | 141 | resource "aws_lambda_function_url" "lambda_url" { 142 | function_name = aws_lambda_function.lambda.function_name 143 | authorization_type = "NONE" 144 | } 145 | -------------------------------------------------------------------------------- /other_examples/lambda_python_api/terraform/locals.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | # Paths for loading the code related to the Lambda Functions 3 | module_path = abspath(path.module) 4 | root_path = abspath("${path.module}/..") 5 | src_root_path = abspath("${path.module}/../src") 6 | lambda_layers_root_path = abspath("${path.module}/../lambda-layers") 7 | } 8 | -------------------------------------------------------------------------------- /other_examples/lambda_python_api/terraform/provider.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = "us-east-1" 3 | 4 | default_tags { 5 | tags = { 6 | "Owner": "Santiago Garcia Arango", 7 | "Source"= "https://github.com/san99tiago/aws-fastapi-lambda", 8 | "Usage"= "Sample project to illustrate a quick easy FastAPI deployment on Lambda Functions" 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /other_examples/lambda_python_api/terraform/variables.tf: -------------------------------------------------------------------------------- 1 | variable "environment" { 2 | type = string 3 | description = "Environment for the deployment" 4 | default = "dev" 5 | } 6 | 7 | variable "main_resources_name" { 8 | type = string 9 | description = "Main resources across the deployment" 10 | default = "curso-devops-python" 11 | } 12 | -------------------------------------------------------------------------------- /other_examples/multiple_instances_based_on_tags/.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.15.1" 6 | hashes = [ 7 | "h1:KPu3MdNXCScye05Sp4JlE9WwhS9k3yD9KRoRDHg5sDE=", 8 | "zh:1d944144f8d613b8090c0c8391e4b205ca036086d70aceb4cdf664856fa8410c", 9 | "zh:2a0ca16a6b12c0ac509f64512f80bd2ed6e7ea0ec369212efd4be3fa65e9773d", 10 | "zh:3f9efdce4f1c320ffd061e8715e1d031deac1be0b959eaa60c25a274925653e4", 11 | "zh:4cf82f3267b0c3e08be29b0345f711ab84ea1ea75f0e8ce81f5a2fe635ba67b4", 12 | "zh:58474a0b7da438e1bcd53e87f10e28830836ff9b46cce5f09413c90952ae4f78", 13 | "zh:6eb1be8afb0314b6b8424fe212b13beeb04f3f24692f0f3ee86c5153c7eb2e63", 14 | "zh:8022da7d3b050d452ce6c679844e13729bdb4e1b3e75dcf68931af17a06b9277", 15 | "zh:8e2683d00fff1df43440d6e7c04a2c1eb432c7d5dacff32fe8ce9045bc948fe6", 16 | "zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425", 17 | "zh:b0c22d9a306e8ac2de57b5291a3d0a7a2c1713e33b7d076005662451afdc4d29", 18 | "zh:ba6b7d7d91388b636145b133da6b4e32620cdc8046352e2dc8f3f0f81ff5d2e2", 19 | "zh:d38a816eb60f4419d99303136a3bb61a0d2df3ca8a1dce2ced9b99bf23efa9f7", 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /other_examples/multiple_instances_based_on_tags/copy.terraform.tfvars: -------------------------------------------------------------------------------- 1 | ami_id = "ami-0022f774911c1d690" 2 | instance_type = "t2.nano" 3 | enable_instances = true 4 | list_of_tags = [ 5 | { 6 | "Environment" : "dev", 7 | "CostCenter" : "DevOps", 8 | "Organization" : "Cool-Organization-1", 9 | "AppCode" : "code-12" 10 | }, 11 | { 12 | "Environment" : "qa", 13 | "CostCenter" : "DevOps", 14 | "Organization" : "Cool-Organization-1", 15 | "AppCode" : "code-12" 16 | }, 17 | { 18 | "Environment" : "dev", 19 | "CostCenter" : "Automation", 20 | "Organization" : "Cool-Organization-1", 21 | "AppCode" : "code-23" 22 | }, 23 | { 24 | "Environment" : "qa", 25 | "CostCenter" : "Automation", 26 | "Organization" : "Cool-Organization-1", 27 | "AppCode" : "code-23" 28 | }, 29 | { 30 | "Environment" : "dev", 31 | "Organization" : "Cool-Organization-2" 32 | }, 33 | { 34 | "Environment" : "qa", 35 | "CostCenter" : "Automation", 36 | }, 37 | { 38 | "AppCode" : "code-34" 39 | } 40 | ] 41 | -------------------------------------------------------------------------------- /other_examples/multiple_instances_based_on_tags/main.tf: -------------------------------------------------------------------------------- 1 | resource "aws_instance" "this" { 2 | count = var.enable_instances == true ? length(var.list_of_tags) : 0 3 | ami = var.ami_id 4 | instance_type = var.instance_type 5 | tags = merge( 6 | { "Name" : "playground-instance-${count.index}" }, 7 | var.list_of_tags[count.index] 8 | ) 9 | } 10 | -------------------------------------------------------------------------------- /other_examples/multiple_instances_based_on_tags/outputs.tf: -------------------------------------------------------------------------------- 1 | output "instance_ips" { 2 | value = aws_instance.this.*.public_ip 3 | } 4 | 5 | output "instance_tags" { 6 | value = aws_instance.this.*.tags 7 | } 8 | -------------------------------------------------------------------------------- /other_examples/multiple_instances_based_on_tags/provider.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = "us-east-1" 3 | 4 | default_tags { 5 | tags = { 6 | "Owner" = "Santiago Garcia Arango", 7 | "Source" = "terraform-playground" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /other_examples/multiple_instances_based_on_tags/terraform.tfvars: -------------------------------------------------------------------------------- 1 | ami_id = "ami-0022f774911c1d690" 2 | instance_type = "t2.micro" 3 | enable_instances = true 4 | list_of_tags = [ 5 | { 6 | "Environment" : "dev", 7 | "CostCenter" : "DevOps", 8 | "Organization" : "Cool-Organization-1", 9 | "AppCode" : "code-12" 10 | }, 11 | { 12 | "Environment" : "qa", 13 | "CostCenter" : "DevOps", 14 | "Organization" : "Cool-Organization-1", 15 | "AppCode" : "code-12" 16 | }, 17 | { 18 | "Environment" : "dev", 19 | "Organization" : "Cool-Organization-2" 20 | } 21 | ] 22 | -------------------------------------------------------------------------------- /other_examples/multiple_instances_based_on_tags/variables.tf: -------------------------------------------------------------------------------- 1 | variable "ami_id" { 2 | type = string 3 | description = "The id of the machine image (AMI) to use for the server" 4 | validation { 5 | condition = can(regex("^((ami-)([a-z0-9_.-]){3,128})$", var.ami_id)) 6 | error_message = "Invalid ami_id variable format regex." 7 | } 8 | } 9 | 10 | variable "instance_type" { 11 | type = string 12 | description = "Type of the EC2 instace to create" 13 | default = "t2.micro" 14 | } 15 | 16 | variable "enable_instances" { 17 | type = bool 18 | description = "Set it to true to deploy instances, false to disable instance deploy" 19 | default = false 20 | } 21 | 22 | variable "list_of_tags" { 23 | type = list(map(string)) 24 | description = "list_of_tags for the EC2 instance" 25 | } 26 | --------------------------------------------------------------------------------