\documentclass[10pt,a4paper]{article} % Packages \usepackage{fancyhdr} % For header and footer \usepackage{multicol} % Allows multicols in tables \usepackage{tabularx} % Intelligent column widths \usepackage{tabulary} % Used in header and footer \usepackage{hhline} % Border under tables \usepackage{graphicx} % For images \usepackage{xcolor} % For hex colours %\usepackage[utf8x]{inputenc} % For unicode character support \usepackage[T1]{fontenc} % Without this we get weird character replacements \usepackage{colortbl} % For coloured tables \usepackage{setspace} % For line height \usepackage{lastpage} % Needed for total page number \usepackage{seqsplit} % Splits long words. %\usepackage{opensans} % Can't make this work so far. Shame. Would be lovely. \usepackage[normalem]{ulem} % For underlining links % Most of the following are not required for the majority % of cheat sheets but are needed for some symbol support. \usepackage{amsmath} % Symbols \usepackage{MnSymbol} % Symbols \usepackage{wasysym} % Symbols %\usepackage[english,german,french,spanish,italian]{babel} % Languages % Document Info \author{Marco Ponton (mponton)} \pdfinfo{ /Title (qk-terraform-module.pdf) /Creator (Cheatography) /Author (Marco Ponton (mponton)) /Subject (QK Terraform Module Cheat Sheet) } % Lengths and widths \addtolength{\textwidth}{6cm} \addtolength{\textheight}{-1cm} \addtolength{\hoffset}{-3cm} \addtolength{\voffset}{-2cm} \setlength{\tabcolsep}{0.2cm} % Space between columns \setlength{\headsep}{-12pt} % Reduce space between header and content \setlength{\headheight}{85pt} % If less, LaTeX automatically increases it \renewcommand{\footrulewidth}{0pt} % Remove footer line \renewcommand{\headrulewidth}{0pt} % Remove header line \renewcommand{\seqinsert}{\ifmmode\allowbreak\else\-\fi} % Hyphens in seqsplit % This two commands together give roughly % the right line height in the tables \renewcommand{\arraystretch}{1.3} \onehalfspacing % Commands \newcommand{\SetRowColor}[1]{\noalign{\gdef\RowColorName{#1}}\rowcolor{\RowColorName}} % Shortcut for row colour \newcommand{\mymulticolumn}[3]{\multicolumn{#1}{>{\columncolor{\RowColorName}}#2}{#3}} % For coloured multi-cols \newcolumntype{x}[1]{>{\raggedright}p{#1}} % New column types for ragged-right paragraph columns \newcommand{\tn}{\tabularnewline} % Required as custom column type in use % Font and Colours \definecolor{HeadBackground}{HTML}{333333} \definecolor{FootBackground}{HTML}{666666} \definecolor{TextColor}{HTML}{333333} \definecolor{DarkBackground}{HTML}{251565} \definecolor{LightBackground}{HTML}{F8F7FA} \renewcommand{\familydefault}{\sfdefault} \color{TextColor} % Header and Footer \pagestyle{fancy} \fancyhead{} % Set header to blank \fancyfoot{} % Set footer to blank \fancyhead[L]{ \noindent \begin{multicols}{3} \begin{tabulary}{5.8cm}{C} \SetRowColor{DarkBackground} \vspace{-7pt} {\parbox{\dimexpr\textwidth-2\fboxsep\relax}{\noindent \hspace*{-6pt}\includegraphics[width=5.8cm]{/web/www.cheatography.com/public/images/cheatography_logo.pdf}} } \end{tabulary} \columnbreak \begin{tabulary}{11cm}{L} \vspace{-2pt}\large{\bf{\textcolor{DarkBackground}{\textrm{QK Terraform Module Cheat Sheet}}}} \\ \normalsize{by \textcolor{DarkBackground}{Marco Ponton (mponton)} via \textcolor{DarkBackground}{\uline{cheatography.com/173169/cs/36481/}}} \end{tabulary} \end{multicols}} \fancyfoot[L]{ \footnotesize \noindent \begin{multicols}{3} \begin{tabulary}{5.8cm}{LL} \SetRowColor{FootBackground} \mymulticolumn{2}{p{5.377cm}}{\bf\textcolor{white}{Cheatographer}} \\ \vspace{-2pt}Marco Ponton (mponton) \\ \uline{cheatography.com/mponton} \\ \end{tabulary} \vfill \columnbreak \begin{tabulary}{5.8cm}{L} \SetRowColor{FootBackground} \mymulticolumn{1}{p{5.377cm}}{\bf\textcolor{white}{Cheat Sheet}} \\ \vspace{-2pt}Not Yet Published.\\ Updated 12th January, 2023.\\ Page {\thepage} of \pageref{LastPage}. \end{tabulary} \vfill \columnbreak \begin{tabulary}{5.8cm}{L} \SetRowColor{FootBackground} \mymulticolumn{1}{p{5.377cm}}{\bf\textcolor{white}{Sponsor}} \\ \SetRowColor{white} \vspace{-5pt} %\includegraphics[width=48px,height=48px]{dave.jpeg} Measure your website readability!\\ www.readability-score.com \end{tabulary} \end{multicols}} \begin{document} \raggedright \raggedcolumns % Set font size to small. Switch to any value % from this page to resize cheat sheet text: % www.emerson.emory.edu/services/latex/latex_169.html \footnotesize % Small font. \begin{multicols*}{3} \begin{tabularx}{5.377cm}{X} \SetRowColor{DarkBackground} \mymulticolumn{1}{x{5.377cm}}{\bf\textcolor{white}{\{\{fa-lightbulb-o\}\} Main Reasons to Create a Module}} \tn % Row 0 \SetRowColor{LightBackground} \mymulticolumn{1}{x{5.377cm}}{Enforce standards, settings, and conventions when deploying resources.} \tn % Row Count 2 (+ 2) % Row 1 \SetRowColor{white} \mymulticolumn{1}{x{5.377cm}}{Offer a larger building block to facilitate resource deployment.} \tn % Row Count 4 (+ 2) % Row 2 \SetRowColor{LightBackground} \mymulticolumn{1}{x{5.377cm}}{Implement logic to simplify users' life and improve Terraform adoption.} \tn % Row Count 6 (+ 2) \hhline{>{\arrayrulecolor{DarkBackground}}-} \end{tabularx} \par\addvspace{1.3em} \begin{tabularx}{5.377cm}{x{1.69218 cm} x{3.28482 cm} } \SetRowColor{DarkBackground} \mymulticolumn{2}{x{5.377cm}}{\bf\textcolor{white}{\{\{fa-question\}\} Naming Convention}} \tn % Row 0 \SetRowColor{LightBackground} BitBucket Project Key & We recommend you use a key that starts with `TF` and add an acronym to identify the main provider/platform (e.g. `TFAZ` = Azure, `TFGC` = GCP, `TFVR` = vRealize Automation, `TFVS` = vSphere, ...). \tn % Row Count 8 (+ 8) % Row 1 \SetRowColor{white} Repository & All repositories/modules {\bf{MUST}} be named using the `terraform-\textless{}provider\textgreater{}-\textless{}name\textgreater{}` convention (e.g. \seqsplit{`terraform-vsphere-windows-vm`}, \seqsplit{`terraform-azurerm-keyvault`}, ...). \tn % Row Count 15 (+ 7) \hhline{>{\arrayrulecolor{DarkBackground}}--} \end{tabularx} \par\addvspace{1.3em} \begin{tabularx}{5.377cm}{x{0.86963 cm} p{0.64078 cm} x{3.06659 cm} } \SetRowColor{DarkBackground} \mymulticolumn{3}{x{5.377cm}}{\bf\textcolor{white}{\{\{fa-folder-open-o\}\} Repository Structure}} \tn % Row 0 \SetRowColor{LightBackground} `/` & - & Root of the module \tn % Row Count 1 (+ 1) % Row 1 \SetRowColor{white} \seqsplit{`/examples`} & \seqsplit{Required} & Examples of how to use the module \tn % Row Count 3 (+ 2) % Row 2 \SetRowColor{LightBackground} \seqsplit{`/images`} & \seqsplit{Optional} & If your documentation includes images, put them in this folder \tn % Row Count 6 (+ 3) % Row 3 \SetRowColor{white} \seqsplit{`/tests`} & \seqsplit{Optional} & If you have Terratest files put there in this folder \tn % Row Count 8 (+ 2) \hhline{>{\arrayrulecolor{DarkBackground}}---} \end{tabularx} \par\addvspace{1.3em} \begin{tabularx}{5.377cm}{x{1.3731 cm} p{0.54924 cm} x{2.65466 cm} } \SetRowColor{DarkBackground} \mymulticolumn{3}{x{5.377cm}}{\bf\textcolor{white}{\{\{fa-file-code-o\}\} Base Module Files}} \tn % Row 0 \SetRowColor{LightBackground} \seqsplit{`.gitignore`} & \seqsplit{Required} & \{\{link="https://git-scm.com/docs/gitignore"\}\}Git ignore\{\{/link\}\} (see also `Security` section) \tn % Row Count 5 (+ 5) % Row 1 \SetRowColor{white} \seqsplit{`.terraform-docs.yml`} & \seqsplit{Required} & \{\{link="https://terraform-docs.io/"\}\}`terraform-docs`\{\{/link\}\} configuration \tn % Row Count 9 (+ 4) % Row 2 \SetRowColor{LightBackground} \seqsplit{`.tfsec/config.yml`} & \seqsplit{Optional} & If \{\{link="https://github.com/aquasecurity/tfsec"\}\}`tfsec`\{\{/link\}\} is enabled for the repository, it should have a configuration file here \tn % Row Count 16 (+ 7) % Row 3 \SetRowColor{white} `locals.tf` & \seqsplit{Optional} & If you use Terraform \{\{link="https://developer.hashicorp.com/terraform/language/values/locals"\}\}locals\{\{/link\}\}, you should put them in this file \tn % Row Count 23 (+ 7) % Row 4 \SetRowColor{LightBackground} `main.tf` & \seqsplit{Required} & Main module code \tn % Row Count 25 (+ 2) % Row 5 \SetRowColor{white} \seqsplit{`outputs.tf`} & \seqsplit{Required} & Definitions of module \{\{link="https://developer.hashicorp.com/terraform/language/values/outputs"\}\}outputs\{\{/link\}\} should be put in this file \tn % Row Count 32 (+ 7) \end{tabularx} \par\addvspace{1.3em} \vfill \columnbreak \begin{tabularx}{5.377cm}{x{1.3731 cm} p{0.54924 cm} x{2.65466 cm} } \SetRowColor{DarkBackground} \mymulticolumn{3}{x{5.377cm}}{\bf\textcolor{white}{\{\{fa-file-code-o\}\} Base Module Files (cont)}} \tn % Row 6 \SetRowColor{LightBackground} \seqsplit{`provider.tf`} & \seqsplit{Required} & Terraform \{\{link="https://developer.hashicorp.com/terraform/language/providers/configuration"\}\}providers configuration\{\{/link\}\} \tn % Row Count 6 (+ 6) % Row 7 \SetRowColor{white} `README.md` & \seqsplit{Required} & Main module documentation (see also QK's README.md Cheat Sheet) \tn % Row Count 9 (+ 3) % Row 8 \SetRowColor{LightBackground} \seqsplit{`variables.tf`} & \seqsplit{Required} & Module \{\{link="https://developer.hashicorp.com/terraform/language/values/variables"\}\}variables\{\{/link\}\} \tn % Row Count 14 (+ 5) \hhline{>{\arrayrulecolor{DarkBackground}}---} \SetRowColor{LightBackground} \mymulticolumn{3}{x{5.377cm}}{If you prefer to organize your code in different `.tf` files, you can do so, but often a single `main.tf` is enough.} \tn \hhline{>{\arrayrulecolor{DarkBackground}}---} \end{tabularx} \par\addvspace{1.3em} \begin{tabularx}{5.377cm}{X} \SetRowColor{DarkBackground} \mymulticolumn{1}{x{5.377cm}}{\bf\textcolor{white}{\{\{fa-code\}\} Coding Conventions \& Style}} \tn % Row 0 \SetRowColor{LightBackground} \mymulticolumn{1}{x{5.377cm}}{Always add comments when useful. This is particularly important to explain reasons behind a specific design, choice of resources or values, edge cases, known bugs, issues or limitations in the code, etc. Do not add comments just for the sake of it (e.g. `\# Create resource foobar`), add comments when the code is not enough.} \tn % Row Count 7 (+ 7) % Row 1 \SetRowColor{white} \mymulticolumn{1}{x{5.377cm}}{Use underscores (`\_`) not dashes when naming resources (e.g. `vm\_image\_name` not `vm-image-name`).} \tn % Row Count 9 (+ 2) % Row 2 \SetRowColor{LightBackground} \mymulticolumn{1}{x{5.377cm}}{When naming variables, check existing modules and re-use existing names and patterns. For example, if module X uses `google\_zone` and you also need to specify the zone, use the same name, not `gcp\_zone`. Same for patterns, if the most common one is `google\_*` use that pattern, not `gcp\_*`.} \tn % Row Count 15 (+ 6) % Row 3 \SetRowColor{white} \mymulticolumn{1}{x{5.377cm}}{Be consistent when naming resources and variables (e.g. don't name something `google\_foo` only to name the next thing `gcp\_bar`).} \tn % Row Count 18 (+ 3) % Row 4 \SetRowColor{LightBackground} \mymulticolumn{1}{x{5.377cm}}{Remember that once your module is published, renaming resources and variables will become a breaking change and may impact existing projects negatively, so try to do it right the first time or chances are we'll need to live with it.} \tn % Row Count 23 (+ 5) % Row 5 \SetRowColor{white} \mymulticolumn{1}{x{5.377cm}}{Validate all user inputs (variables) when possible. Follow the "fail early" mantra, do not let user create 13 resources only to fail on the 14th when you can prevent it.} \tn % Row Count 27 (+ 4) % Row 6 \SetRowColor{LightBackground} \mymulticolumn{1}{x{5.377cm}}{When validating variable inputs, use multiple `validation` blocks when doing different checks. This allows you to provide more meaningful error messages.} \tn % Row Count 31 (+ 4) \end{tabularx} \par\addvspace{1.3em} \vfill \columnbreak \begin{tabularx}{5.377cm}{X} \SetRowColor{DarkBackground} \mymulticolumn{1}{x{5.377cm}}{\bf\textcolor{white}{\{\{fa-code\}\} Coding Conventions \& Style (cont)}} \tn % Row 7 \SetRowColor{LightBackground} \mymulticolumn{1}{x{5.377cm}}{When it makes sense, provide useful defaults for variables.} \tn % Row Count 2 (+ 2) % Row 8 \SetRowColor{white} \mymulticolumn{1}{x{5.377cm}}{Start the description of optional variables by "**OPTIONAL:** " followed by the description.} \tn % Row Count 4 (+ 2) % Row 9 \SetRowColor{LightBackground} \mymulticolumn{1}{x{5.377cm}}{Do not use {\emph{explicit}} dependencies (`depends\_on`) unless necessary and you understand the impacts. Always use {\emph{implicit}} dependencies instead.} \tn % Row Count 7 (+ 3) \hhline{>{\arrayrulecolor{DarkBackground}}-} \end{tabularx} \par\addvspace{1.3em} \begin{tabularx}{5.377cm}{X} \SetRowColor{DarkBackground} \mymulticolumn{1}{x{5.377cm}}{\bf\textcolor{white}{\{\{fa-lock\}\} Version Constraints}} \tn % Row 0 \SetRowColor{LightBackground} \mymulticolumn{1}{x{5.377cm}}{Your `provider.tf` file {\bf{MUST}} include \{\{link="https://developer.hashicorp.com/terraform/language/expressions/version-constraints"\}\}version constraints\{\{/link\}\}.} \tn % Row Count 4 (+ 4) % Row 1 \SetRowColor{white} \mymulticolumn{1}{x{5.377cm}}{Version constraints of each provider should usually be locked to the major version of the provider (e.g. `version = "\textgreater{}= 2.0, \textless{} 3.0"`) unless fully tested with multiple major versions".} \tn % Row Count 8 (+ 4) % Row 2 \SetRowColor{LightBackground} \mymulticolumn{1}{x{5.377cm}}{If your code requires a specific minor of fix version, use the correct constraint and document why (e.g. `Version 1.2.0 or newer is required to prevent issue when updating resources of type XYZ``).} \tn % Row Count 12 (+ 4) \hhline{>{\arrayrulecolor{DarkBackground}}-} \end{tabularx} \par\addvspace{1.3em} \begin{tabularx}{5.377cm}{X} \SetRowColor{DarkBackground} \mymulticolumn{1}{x{5.377cm}}{\bf\textcolor{white}{\{\{fa-code-fork\}\} Semantic Versioning}} \tn % Row 0 \SetRowColor{LightBackground} \mymulticolumn{1}{x{5.377cm}}{Terraform modules {\bf{MUST}} follow \{\{link="https://semver.org/\#summary"\}\}Semantic Versioning\{\{/link\}\}} \tn % Row Count 2 (+ 2) % Row 1 \SetRowColor{white} \mymulticolumn{1}{x{5.377cm}}{Always pay attention to the changes you make to a module! Terraform can be very finicky and what may look like a simple change may trigger a destroy operation in existing project code.} \tn % Row Count 6 (+ 4) % Row 2 \SetRowColor{LightBackground} \mymulticolumn{1}{x{5.377cm}}{Follow Semantic Versioning {\bf{rules}}, do not fall for the "small changes" should not change the major version number mentality. For example, if you fix a typo in a variable name, any existing code using this variable will break, as such, small change = breaking change = new major version.} \tn % Row Count 12 (+ 6) \hhline{>{\arrayrulecolor{DarkBackground}}-} \end{tabularx} \par\addvspace{1.3em} \begin{tabularx}{5.377cm}{X} \SetRowColor{DarkBackground} \mymulticolumn{1}{x{5.377cm}}{\bf\textcolor{white}{\{\{fa-arrow-up\}\} Project Upgrade Paths}} \tn \SetRowColor{white} \mymulticolumn{1}{x{5.377cm}}{When introducing breaking changes, always think about the best implementation for an upgrade path. We recommend you also create a `upgrade-vX-to-vY.md` (for example: `update-v2-to-v3.md`) file with instructions on how to upgrade existing projects to the new major module version from the last major version. This is particularly important if the breaking change may introduce data loss (trigger a Terraform destroy operation).% Row Count 9 (+ 9) } \tn \hhline{>{\arrayrulecolor{DarkBackground}}-} \end{tabularx} \par\addvspace{1.3em} \begin{tabularx}{5.377cm}{X} \SetRowColor{DarkBackground} \mymulticolumn{1}{x{5.377cm}}{\bf\textcolor{white}{\{\{fa-book\}\} Documentation}} \tn % Row 0 \SetRowColor{LightBackground} \mymulticolumn{1}{x{5.377cm}}{Your module {\bf{MUST}} include proper documentation. See QK's README.md Cheat Sheet for details.} \tn % Row Count 2 (+ 2) % Row 1 \SetRowColor{white} \mymulticolumn{1}{x{5.377cm}}{Documentation {\bf{MUST}} be part of the repository and {\bf{MUST}} be written in Markdown. Feel free to split documentation into multiple files if needed, but always make the `README.md` file the main point of entry.} \tn % Row Count 7 (+ 5) % Row 2 \SetRowColor{LightBackground} \mymulticolumn{1}{x{5.377cm}}{We also recommend you review some of QK's GCP VM modules (e.g. \{\{link="https://gitprd.cn.ca/projects/TFGC/repos/terraform-google-windows-vm/browse"\}\}Windows VM\{\{/link\}\} for some sample README files.} \tn % Row Count 11 (+ 4) \hhline{>{\arrayrulecolor{DarkBackground}}-} \end{tabularx} \par\addvspace{1.3em} \begin{tabularx}{5.377cm}{X} \SetRowColor{DarkBackground} \mymulticolumn{1}{x{5.377cm}}{\bf\textcolor{white}{\{\{fa-file-text-o\}\} terraform-docs}} \tn % Row 0 \SetRowColor{LightBackground} \mymulticolumn{1}{x{5.377cm}}{Always ensure you have proper `.terraform-docs.yml` in your repository and run `terraform-docs .` after making changes to your module to update documentation} \tn % Row Count 4 (+ 4) \hhline{>{\arrayrulecolor{DarkBackground}}-} \SetRowColor{LightBackground} \mymulticolumn{1}{x{5.377cm}}{Look into one of QK's latest Terraform module for a recent copy of the `.terraform-docs.yml` file.} \tn \hhline{>{\arrayrulecolor{DarkBackground}}-} \end{tabularx} \par\addvspace{1.3em} \begin{tabularx}{5.377cm}{X} \SetRowColor{DarkBackground} \mymulticolumn{1}{x{5.377cm}}{\bf\textcolor{white}{\{\{fa-shield\}\} Security}} \tn % Row 0 \SetRowColor{LightBackground} \mymulticolumn{1}{x{5.377cm}}{When one or more providers in your module are supported by the \{\{link="https://github.com/aquasecurity/tfsec"\}\}`tfsec`\{\{/link\}\} tool, you should create a base `.tfsec/config.yml` and run the tool against your module to validate it. If any issues are found, fix them or if not possible, add the proper exceptions to the `config.yml` file and document them.} \tn % Row Count 8 (+ 8) % Row 1 \SetRowColor{white} \mymulticolumn{1}{x{5.377cm}}{\{\{fa-warning\}\} Always exclude `.tfvars`, state files, and any secrets using `.gitignore` before you commit code.} \tn % Row Count 11 (+ 3) \hhline{>{\arrayrulecolor{DarkBackground}}-} \end{tabularx} \par\addvspace{1.3em} \begin{tabularx}{5.377cm}{X} \SetRowColor{DarkBackground} \mymulticolumn{1}{x{5.377cm}}{\bf\textcolor{white}{\{\{fa-certificate\}\} Releases}} \tn % Row 0 \SetRowColor{LightBackground} \mymulticolumn{1}{x{5.377cm}}{Always tag official releases with a proper `vX.Y.Z` semantic version tag.} \tn % Row Count 2 (+ 2) % Row 1 \SetRowColor{white} \mymulticolumn{1}{x{5.377cm}}{Always ensure your README and any other documentation is up-to-date before publishing a new release.} \tn % Row Count 4 (+ 2) % Row 2 \SetRowColor{LightBackground} \mymulticolumn{1}{x{5.377cm}}{Always provide 2-3 up-to-date working examples with your modules. Exception of any authentication and access, these should work out-of-the-box for any user that wants to deploy them.} \tn % Row Count 8 (+ 4) \hhline{>{\arrayrulecolor{DarkBackground}}-} \end{tabularx} \par\addvspace{1.3em} \begin{tabularx}{5.377cm}{X} \SetRowColor{DarkBackground} \mymulticolumn{1}{x{5.377cm}}{\bf\textcolor{white}{\{\{fa-gift\}\} Tips}} \tn % Row 0 \SetRowColor{LightBackground} \mymulticolumn{1}{x{5.377cm}}{If your module relies on other modules, always lock their version using either version constraints (if using registry) or `git` URL `ref` (e.g. `?ref=v1.2.3`).} \tn % Row Count 4 (+ 4) % Row 1 \SetRowColor{white} \mymulticolumn{1}{x{5.377cm}}{When creating examples for your module, provide at least one `minimal` and one `complete` example.} \tn % Row Count 6 (+ 2) % Row 2 \SetRowColor{LightBackground} \mymulticolumn{1}{x{5.377cm}}{Include all necessary files in your examples so they can be used as a starting point for a new project. For example, include a `.gitignore` even if not needed for the example to be functional.} \tn % Row Count 10 (+ 4) \hhline{>{\arrayrulecolor{DarkBackground}}-} \end{tabularx} \par\addvspace{1.3em} % That's all folks \end{multicols*} \end{document}