[{"data":1,"prerenderedAt":210},["ShallowReactive",2],{"content-guides-building-serverless-applications-with-terraform-08-modularizing-your-iac-projects":3},{"markdown":4,"frontMatterAttributes":5,"bodyRaw":23,"contributorPaths":24,"menuType":29,"contentName":30,"slug":31,"readingTime":32,"menu":33,"nextDocItem":161,"previousDocItem":131},"\u003Cp>In previous chapters, you&#39;ve learned the foundational steps of constructing a serverless application IaC using a single \u003Ccode>main.tf\u003C\u002Fcode> file. In this chapter, you&#39;ll learn to elevate your IaC by transitioning from a basic one-file setup to a modular configuration. Your goal is to ensure scalability, maintainability, and the adoption of best practices that align with the demands of contemporary IT infrastructures.\u003C\u002Fp>\n\u003Cp>In real-world scenarios, engineers would typically prefer a modular, decoupled approach to their IaC. They want to maintain the development flexibility, while ensuring operational efficiency. For example, it is common to separate resource definition and environment-specific configuration by segmenting your IaC project into different \u003Ccode>.tf\u003C\u002Fcode> files. Another common approach is to separate application logic code from IaC. This allows engineering teams to enhance agility across development, while enforcing cohesiveness throughout multiple environments and the product lifecycle. \u003C\u002Fp>\n\u003Ch2>Terraform modules\u003C\u002Fh2>\n\u003Cp>In order to support modular IaC definitions, Terraform provides support for Modules. Modules help to encapsulate resources for multiple related segments of your application. In previous chapters you&#39;ve seen the \u003Ccode>main.tf\u003C\u002Fcode> file in the root working directory. This was an implicitly used \u003Cem>root module\u003C\u002Fem>. Modules can have input parameters, or variables, commonly defined in a \u003Ccode>variables.tf\u003C\u002Fcode> file, as well as outputs, commonly defined in an \u003Ccode>outputs.tf\u003C\u002Fcode> file, as you&#39;ve seen in previous chapters. \u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-bash\">module-root-directory\u002F\n├── variables.tf\n├── main.tf\n└── outputs.tf\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>A module can include other modules, optionally passing down variable values. This is called using a child module. The syntax for including a child module is as follows. Outputs from child modules can be accessed from the parent module. \u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-hcl\">module &quot;child_module_name&quot; {\n  source = &quot;.\u002Fchild-module-directory&quot;\n  variable1 = value1\n  variable2 = value2\n  ...\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Read more about Terraform Modules in the \u003Ca href=\"https:\u002F\u002Fdeveloper.hashicorp.com\u002Fterraform\u002Flanguage\u002Fmodules\">Terraform docs\u003C\u002Fa>. \u003C\u002Fp>\n\u003Ch2>Directory structure\u003C\u002Fh2>\n\u003Cp>It is important to understand that there&#39;s no one-size-fits-all directory structure. Depending on factors like your existing Terraform practices or your anticipated deployment model, you might already have a preferred approach in your enterprise. When designing your project directory structure, it is important to understand not only \u003Cem>how\u003C\u002Fem> you&#39;re going to segment your files and modules, but also \u003Cem>why\u003C\u002Fem> you&#39;re going to organize it in a particular way. For simplicity, in this guide we&#39;ll organize Terraform modules by resource types, while decoupling source code into its own separate directory. \u003C\u002Fp>\n\u003Cp>Below layout can serve as a good starting point for modularizing Terraform configurations and separating application source code into its own directory:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-bash\">project-root-directory\u002F\n├── terraform \u002F\n│   ├── main.tf\n│   ├── variables.tf\n│   ├── modules\u002F\n│   └── environments\u002F\n│\n└── lambda \u002F\n    └── my-function-1\u002F\n        └── index.mjs\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cul>\n\u003Cli>The \u003Ccode>terraform\u002F\u003C\u002Fcode> directory holds all Terraform IaC files. You put module definitions under \u003Ccode>modules\u002F\u003C\u002Fcode> and different environment definitions under \u003Ccode>environments\u002F\u003C\u002Fcode>.\u003C\u002Fli>\n\u003Cli>The \u003Ccode>lambda\u002F\u003C\u002Fcode> directory contains your AWS Lambda functions. You would have a directory per function here, so you can add your code dependencies, such as \u003Ccode>node_modules\u003C\u002Fcode>, and other code related artifacts.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>For reusability and clarity, encapsulate each resource type in its own module. Create individual folders under \u003Ccode>modules\u002F\u003C\u002Fcode> for each module. It is a good idea to keep related resources like execution roles for Lambda functions in the same module as the Lambda function. \u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-bash\">terraform\u002F\n├── modules\u002F\n│   ├── apigateway\u002F\n│   ├── lambdas\u002F\n│   ├── sqs\u002F\n│   └── storage\u002F\n│\n└── environments\u002F\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Each module should have its own \u003Ccode>main.tf\u003C\u002Fcode>, \u003Ccode>variables.tf\u003C\u002Fcode>, and \u003Ccode>outputs.tf\u003C\u002Fcode> files. \u003C\u002Fp>\n\u003Cp>See below the outline of the \u003Ccode>storage\u003C\u002Fcode> module of the serverless application you&#39;ve learned to build in previous chapters. It uses variables (\u003Ccode>variables.tf\u003C\u002Fcode>) to receive source and destination bucket names, as well as environment tag, creates required resources (\u003Ccode>main.tf\u003C\u002Fcode>), and outputs ARNs and IDs of created resources (\u003Ccode>outputs.tf\u003C\u002Fcode>). The internal logic is encapsulated within the module.\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-hcl\"># variables.tf\nvariable &quot;src_bucket_name&quot; {\n  type = string\n}\n\nvariable &quot;dst_bucket_name&quot; {\n  type = string\n}\n\nvariable &quot;tag_environment&quot; {\n  type = string\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cpre>\u003Ccode class=\"language-hcl\"># main.tf\nresource &quot;aws_s3_bucket&quot; &quot;src_bucket&quot; {\n  bucket = var.src_bucket_name\n  tags = {\n    environment = var.tag_environment\n  }\n}\n\n... redacted ... \n\nresource &quot;aws_s3_bucket&quot; &quot;dst_bucket&quot; {\n  bucket = var.dst_bucket_name\n\n  tags = {\n    environment = var.tag_environment\n  }\n}\n\n... redacted ... \n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cpre>\u003Ccode class=\"language-hcl\"># outputs.tf\noutput &quot;src_bucket_arn&quot; {\n  value = aws_s3_bucket.src_bucket.arn\n}\n\noutput &quot;src_bucket_id&quot; {\n  value = aws_s3_bucket.src_bucket.id\n}\n\noutput &quot;dst_bucket_arn&quot; {\n  value = aws_s3_bucket.dst_bucket.arn\n}\n\noutput &quot;dst_bucket_id&quot; {\n  value = aws_s3_bucket.dst_bucket.id\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>See below for a full visual representation of a modularized project structure. \u003C\u002Fp>\n\u003Cp>\u003Cimg src=\"\u002Fassets\u002Fexternal\u002Fguides\u002Fbuilding-serverless-applications-with-terraform\u002Fassets\u002Fmodule8.png\" alt=\"\">\u003C\u002Fp>\n\u003Ch2>Environments\u003C\u002Fh2>\n\u003Cp>Differentiating resource configurations based on environments, such as development, staging, and production, enables organizations to maintain a clean separation of concerns. Each environment can contain its specific set of defaults, configurations, and resource allocations tailored to its purpose. This segregation ensures that experimental changes do not impact live systems, provides a controlled space for testing and validation, and allows for optimal resource utilization. Moreover, it simplifies the process of environment-specific configurations, making the infrastructure more modular and easier to manage, thus streamlining the overall deployment and scaling processes.\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-bash\">terraform\u002F\n├── modules\u002F\n└── environments\u002F\n    ├── development\u002F\n    │   └── terraform.tfvars\n    ├── staging\u002F\n    │   └── terraform.tfvars\n    └── production\u002F\n        └── terraform.tfvars\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Each environment directory can have its own \u003Ccode>terraform.tfvars\u003C\u002Fcode> file, which contains variable values for that specific environment. \u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-hcl\"># environments\u002Fdevelopment\u002Fterraform.tfvars\nenvironment        = &quot;development&quot;\nlambda_memory_size = 256\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cpre>\u003Ccode class=\"language-hcl\"># environments\u002Fproduction\u002Fterraform.tfvars\nenvironment        = &quot;production&quot;\nlambda_memory_size = 1024\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>When applying the Terraform configuration, you can either explicitly pass variable values, or specify which environment variables file to use. \u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-bash\">terraform apply \\\n  -var=&quot;environment=production&quot; \\\n  -var=&quot;lambda_memory_size=1024&quot;\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cpre>\u003Ccode class=\"language-bash\">terraform apply \\\n  --var-file=&quot;environments\u002Fproduction\u002Fterraform.tfvars&quot;\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2>Externalizing configurations\u003C\u002Fh2>\n\u003Cp>While it is possible to store variable configuration values in a \u003Ccode>.tfvars\u003C\u002Fcode> file, you can go one step further and externalize them to a designated cloud service. \u003Ca href=\"https:\u002F\u002Faws.amazon.com\u002Fsystems-manager\u002Ffeatures\u002F#Parameter_Store\">AWS Systems Manager Parameter Store (SSM)\u003C\u002Fa> provides centralized storage for configuration data. Externalizing the values to the SSM for environment differentiation allows to ensure a reinforced boundary separation. Each environment — whether it&#39;s development, staging, or production — has its distinct set of SSM parameters. As these parameters traverse their dedicated pipelines, the pipeline role specific to a particular environment is restricted to read only that environment&#39;s SSM parameters. This method not only enhances security and confines sensitive data but also streamlines configuration management. By tightly coupling roles with their respective environment&#39;s parameters, clear boundaries are maintained, preventing inadvertent data access or overlaps, and ensuring a coherent and safeguarded deployment process. \u003C\u002Fp>\n\u003Cp>In order to create an externalized variable value for Terraform, you need to follow three steps\u003C\u002Fp>\n\u003Col>\n\u003Cli>Create an SSM Parameter, for example\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Cul>\n\u003Cli>Name = \u003Ccode>\u002Fconfig\u002Fdev\u002Fresource-name\u003C\u002Fcode>, value = \u003Ccode>Development Resource\u003C\u002Fcode>\u003C\u002Fli>\n\u003Cli>Name = \u003Ccode>\u002Fconfig\u002Fprod\u002Fresource-name\u003C\u002Fcode>, value = \u003Ccode>Production Resource\u003C\u002Fcode>\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Col start=\"2\">\n\u003Cli>Retrieve SSM Parameters value, for example\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Cpre>\u003Ccode class=\"language-hcl\"># terraform\u002Fenvironments\u002Fdev\u002Fvariables.tf\ndata &quot;aws_ssm_parameter&quot; &quot;resource_name&quot; {\n  name = &quot;\u002Fconfig\u002Fdev\u002Fresource-name&quot;\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cpre>\u003Ccode class=\"language-hcl\"># terraform\u002Fenvironments\u002Fprod\u002Fvariables.tf\ndata &quot;aws_ssm_parameter&quot; &quot;resource_name&quot; {\n  name = &quot;\u002Fconfig\u002Fprod\u002Fresource-name&quot;\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cpre>\u003Ccode class=\"language-hcl\">variable &quot;resource_name&quot; {\n  description = &quot;The resource name, value is applied dynamically per environment&quot;\n  default     = data.aws_ssm_parameter.resource_name.value\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Col start=\"3\">\n\u003Cli>Pass the populated variable to relevant modules:\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Cpre>\u003Ccode class=\"language-hcl\"># terraform\u002Fenvironments\u002Fdev\u002Fmain.tf\nmodule &quot;some-module&quot; {\n  source = &quot;..\u002F..\u002Fmodules\u002Fsome-module&quot;\n  resource_name = var.resource_name\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>This approach ensures that the configurations in each environment fetch their specific parameters from SSM, and then those parameters are passed to the modules, which in turn apply them. This maintains a clean and modular project structure.\u003C\u002Fp>\n\u003Ch2>Conclusion\u003C\u002Fh2>\n\u003Cp>The deliberate separation of resources and environments in a directory structure ensures a clear and logical organization of resources, tailored specifically for each stage of the application&#39;s lifecycle. This modular approach guarantees that changes in one environment do not inadvertently impact another, fostering safer development and deployment practices.\u003C\u002Fp>\n\u003Cp>Furthermore, the integration of AWS Systems Manager Parameter Store (SSM) into this structure amplifies the benefits. By centralizing configuration data within SSM, you eliminate hardcoded values, thereby enhancing security and maintainability. Additionally, by pulling environment-specific parameters from SSM, you ensure that each environment is uniquely configured, further strengthening the boundaries between them.\u003C\u002Fp>\n\u003Cp>In essence, the combination of a well-organized environment-based folder structure with the dynamic, centralized parameter management offered by SSM results in a robust, scalable, and secure infrastructure setup. It paves the way for efficient development, testing, and deployment processes, ensuring that the right configurations are always applied to the right environments.\u003C\u002Fp>\n\u003Ch2>Recap\u003C\u002Fh2>\n\u003Cp>In this chapter you&#39;ve learned how to:\u003C\u002Fp>\n\u003Col>\n\u003Cli>Define a Terraform module\u003C\u002Fli>\n\u003Cli>Organize your Terraform IaC into a collection of logical modules\u003C\u002Fli>\n\u003Cli>Support multiple environments via \u003Ccode>.tfvars\u003C\u002Fcode> files or with the Systems Manager Parameter Store (SSM) service.\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Ch2>Next Steps\u003C\u002Fh2>\n\u003Cp>The next chapter will summarize this guide, as well as provide you with a collection of actionable next steps to continue your learning journey with Serverless and Terraform.\u003C\u002Fp>\n",{"title":6,"order":7,"authors":8,"resources":11},"8. Modularizing your IaC projects",8,[9,10],"Anton Aleksandrov","Debasis Rath",[12,16,19],{"link":13,"text":14,"type":15},"https:\u002F\u002Fregistry.terraform.io\u002Fproviders\u002Fhashicorp\u002Faws\u002Flatest\u002Fdocs","AWS Terraform Provider","Documentation",{"link":17,"text":18,"type":15},"https:\u002F\u002Fdeveloper.hashicorp.com\u002Fterraform\u002Flanguage\u002Fmodules","Terraform Modules",{"link":20,"text":21,"type":22},"https:\u002F\u002Fgithub.com\u002Faws-samples\u002Fbuilding-serverless-applications-with-terraform","Sample project source code","Sample","In previous chapters, you've learned the foundational steps of constructing a serverless application IaC using a single `main.tf` file. In this chapter, you'll learn to elevate your IaC by transitioning from a basic one-file setup to a modular configuration. Your goal is to ensure scalability, maintainability, and the adoption of best practices that align with the demands of contemporary IT infrastructures.\n\nIn real-world scenarios, engineers would typically prefer a modular, decoupled approach to their IaC. They want to maintain the development flexibility, while ensuring operational efficiency. For example, it is common to separate resource definition and environment-specific configuration by segmenting your IaC project into different `.tf` files. Another common approach is to separate application logic code from IaC. This allows engineering teams to enhance agility across development, while enforcing cohesiveness throughout multiple environments and the product lifecycle. \n\n## Terraform modules \n\nIn order to support modular IaC definitions, Terraform provides support for Modules. Modules help to encapsulate resources for multiple related segments of your application. In previous chapters you've seen the `main.tf` file in the root working directory. This was an implicitly used *root module*. Modules can have input parameters, or variables, commonly defined in a `variables.tf` file, as well as outputs, commonly defined in an `outputs.tf` file, as you've seen in previous chapters. \n\n```bash\nmodule-root-directory\u002F\n├── variables.tf\n├── main.tf\n└── outputs.tf\n```\n\nA module can include other modules, optionally passing down variable values. This is called using a child module. The syntax for including a child module is as follows. Outputs from child modules can be accessed from the parent module. \n\n```hcl\nmodule \"child_module_name\" {\n  source = \".\u002Fchild-module-directory\"\n  variable1 = value1\n  variable2 = value2\n  ...\n}\n```\n\nRead more about Terraform Modules in the [Terraform docs](https:\u002F\u002Fdeveloper.hashicorp.com\u002Fterraform\u002Flanguage\u002Fmodules). \n\n## Directory structure\n\nIt is important to understand that there's no one-size-fits-all directory structure. Depending on factors like your existing Terraform practices or your anticipated deployment model, you might already have a preferred approach in your enterprise. When designing your project directory structure, it is important to understand not only *how* you're going to segment your files and modules, but also *why* you're going to organize it in a particular way. For simplicity, in this guide we'll organize Terraform modules by resource types, while decoupling source code into its own separate directory. \n\nBelow layout can serve as a good starting point for modularizing Terraform configurations and separating application source code into its own directory:\n\n```bash\nproject-root-directory\u002F\n├── terraform \u002F\n│   ├── main.tf\n│   ├── variables.tf\n│   ├── modules\u002F\n│   └── environments\u002F\n│\n└── lambda \u002F\n    └── my-function-1\u002F\n        └── index.mjs\n```\n\n- The `terraform\u002F` directory holds all Terraform IaC files. You put module definitions under `modules\u002F` and different environment definitions under `environments\u002F`.\n- The `lambda\u002F` directory contains your AWS Lambda functions. You would have a directory per function here, so you can add your code dependencies, such as `node_modules`, and other code related artifacts. \n\nFor reusability and clarity, encapsulate each resource type in its own module. Create individual folders under `modules\u002F` for each module. It is a good idea to keep related resources like execution roles for Lambda functions in the same module as the Lambda function. \n\n```bash\nterraform\u002F\n├── modules\u002F\n│   ├── apigateway\u002F\n│   ├── lambdas\u002F\n│   ├── sqs\u002F\n│   └── storage\u002F\n│\n└── environments\u002F\n```\n\nEach module should have its own `main.tf`, `variables.tf`, and `outputs.tf` files. \n\nSee below the outline of the `storage` module of the serverless application you've learned to build in previous chapters. It uses variables (`variables.tf`) to receive source and destination bucket names, as well as environment tag, creates required resources (`main.tf`), and outputs ARNs and IDs of created resources (`outputs.tf`). The internal logic is encapsulated within the module.\n\n```hcl\n# variables.tf\nvariable \"src_bucket_name\" {\n  type = string\n}\n\nvariable \"dst_bucket_name\" {\n  type = string\n}\n\nvariable \"tag_environment\" {\n  type = string\n}\n```\n\n```hcl\n# main.tf\nresource \"aws_s3_bucket\" \"src_bucket\" {\n  bucket = var.src_bucket_name\n  tags = {\n    environment = var.tag_environment\n  }\n}\n\n... redacted ... \n\nresource \"aws_s3_bucket\" \"dst_bucket\" {\n  bucket = var.dst_bucket_name\n\n  tags = {\n    environment = var.tag_environment\n  }\n}\n\n... redacted ... \n```\n\n```hcl\n# outputs.tf\noutput \"src_bucket_arn\" {\n  value = aws_s3_bucket.src_bucket.arn\n}\n\noutput \"src_bucket_id\" {\n  value = aws_s3_bucket.src_bucket.id\n}\n\noutput \"dst_bucket_arn\" {\n  value = aws_s3_bucket.dst_bucket.arn\n}\n\noutput \"dst_bucket_id\" {\n  value = aws_s3_bucket.dst_bucket.id\n}\n```\n\nSee below for a full visual representation of a modularized project structure. \n\n![](\u002Fassets\u002Fexternal\u002Fguides\u002Fbuilding-serverless-applications-with-terraform\u002Fassets\u002Fmodule8.png)\n\n## Environments\n\nDifferentiating resource configurations based on environments, such as development, staging, and production, enables organizations to maintain a clean separation of concerns. Each environment can contain its specific set of defaults, configurations, and resource allocations tailored to its purpose. This segregation ensures that experimental changes do not impact live systems, provides a controlled space for testing and validation, and allows for optimal resource utilization. Moreover, it simplifies the process of environment-specific configurations, making the infrastructure more modular and easier to manage, thus streamlining the overall deployment and scaling processes.\n\n```bash\nterraform\u002F\n├── modules\u002F\n└── environments\u002F\n    ├── development\u002F\n    │   └── terraform.tfvars\n    ├── staging\u002F\n    │   └── terraform.tfvars\n    └── production\u002F\n        └── terraform.tfvars\n```\n\nEach environment directory can have its own `terraform.tfvars` file, which contains variable values for that specific environment. \n\n```hcl\n# environments\u002Fdevelopment\u002Fterraform.tfvars\nenvironment        = \"development\"\nlambda_memory_size = 256\n```\n\n```hcl\n# environments\u002Fproduction\u002Fterraform.tfvars\nenvironment        = \"production\"\nlambda_memory_size = 1024\n```\n\nWhen applying the Terraform configuration, you can either explicitly pass variable values, or specify which environment variables file to use. \n\n```bash\nterraform apply \\\n  -var=\"environment=production\" \\\n  -var=\"lambda_memory_size=1024\"\n```\n\n```bash\nterraform apply \\\n  --var-file=\"environments\u002Fproduction\u002Fterraform.tfvars\"\n```\n\n## Externalizing configurations\n\nWhile it is possible to store variable configuration values in a `.tfvars` file, you can go one step further and externalize them to a designated cloud service. [AWS Systems Manager Parameter Store (SSM)](https:\u002F\u002Faws.amazon.com\u002Fsystems-manager\u002Ffeatures\u002F#Parameter_Store) provides centralized storage for configuration data. Externalizing the values to the SSM for environment differentiation allows to ensure a reinforced boundary separation. Each environment — whether it's development, staging, or production — has its distinct set of SSM parameters. As these parameters traverse their dedicated pipelines, the pipeline role specific to a particular environment is restricted to read only that environment's SSM parameters. This method not only enhances security and confines sensitive data but also streamlines configuration management. By tightly coupling roles with their respective environment's parameters, clear boundaries are maintained, preventing inadvertent data access or overlaps, and ensuring a coherent and safeguarded deployment process. \n\nIn order to create an externalized variable value for Terraform, you need to follow three steps\n\n1. Create an SSM Parameter, for example\n  - Name = `\u002Fconfig\u002Fdev\u002Fresource-name`, value = `Development Resource`\n  - Name = `\u002Fconfig\u002Fprod\u002Fresource-name`, value = `Production Resource`\n\n2. Retrieve SSM Parameters value, for example\n\n  ```hcl\n  # terraform\u002Fenvironments\u002Fdev\u002Fvariables.tf\n  data \"aws_ssm_parameter\" \"resource_name\" {\n    name = \"\u002Fconfig\u002Fdev\u002Fresource-name\"\n  }\n  ```\n\n  ```hcl\n  # terraform\u002Fenvironments\u002Fprod\u002Fvariables.tf\n  data \"aws_ssm_parameter\" \"resource_name\" {\n    name = \"\u002Fconfig\u002Fprod\u002Fresource-name\"\n  }\n  ```\n\n  ```hcl\n  variable \"resource_name\" {\n    description = \"The resource name, value is applied dynamically per environment\"\n    default     = data.aws_ssm_parameter.resource_name.value\n  }\n  ```\n\n3. Pass the populated variable to relevant modules:\n\n  ```hcl\n  # terraform\u002Fenvironments\u002Fdev\u002Fmain.tf\n  module \"some-module\" {\n    source = \"..\u002F..\u002Fmodules\u002Fsome-module\"\n    resource_name = var.resource_name\n  }\n  ```\n\nThis approach ensures that the configurations in each environment fetch their specific parameters from SSM, and then those parameters are passed to the modules, which in turn apply them. This maintains a clean and modular project structure.\n\n## Conclusion\n\nThe deliberate separation of resources and environments in a directory structure ensures a clear and logical organization of resources, tailored specifically for each stage of the application's lifecycle. This modular approach guarantees that changes in one environment do not inadvertently impact another, fostering safer development and deployment practices.\n\nFurthermore, the integration of AWS Systems Manager Parameter Store (SSM) into this structure amplifies the benefits. By centralizing configuration data within SSM, you eliminate hardcoded values, thereby enhancing security and maintainability. Additionally, by pulling environment-specific parameters from SSM, you ensure that each environment is uniquely configured, further strengthening the boundaries between them.\n\nIn essence, the combination of a well-organized environment-based folder structure with the dynamic, centralized parameter management offered by SSM results in a robust, scalable, and secure infrastructure setup. It paves the way for efficient development, testing, and deployment processes, ensuring that the right configurations are always applied to the right environments.\n\n## Recap\n\nIn this chapter you've learned how to:\n\n1. Define a Terraform module\n2. Organize your Terraform IaC into a collection of logical modules\n3. Support multiple environments via `.tfvars` files or with the Systems Manager Parameter Store (SSM) service. \n\n## Next Steps\n\nThe next chapter will summarize this guide, as well as provide you with a collection of actionable next steps to continue your learning journey with Serverless and Terraform.\n",[25,26,27,28],"content\u002Fcontributors\u002Fanton-aleksandrov.json","content\u002Fcontributors\u002Fdebasis-rath.json","content\u002Fcontributors\u002Fmatt-ridehalgh.json","content\u002Fcontributors\u002Fluis-cerezo.json","LIST","Building Serverless Applications with Terraform","\u002Fcontent\u002Fguides\u002Fbuilding-serverless-applications-with-terraform\u002F08-modularizing-your-iac-projects","8 min",[34],{"title":35,"content":36},"Guide",[37,56,72,85,103,116,131,153,161,176,194],{"title":38,"order":39,"authors":40,"resources":41,"time":52,"path":53,"id":54,"link":55},"1. Introduction",1,[9,10],[42,46,49],{"link":43,"text":44,"type":45},"https:\u002F\u002Faws.amazon.com\u002Fserverless\u002Fsam\u002F","AWS Serverless Application Model (SAM)","link",{"link":47,"text":48,"type":45},"https:\u002F\u002Faws.amazon.com\u002Fcdk\u002F","AWS Cloud Development Kit (CDK)",{"link":50,"text":51,"type":45},"https:\u002F\u002Fwww.terraform.io\u002F","Hashicorp Terraform","4 min","01-introduction","01-introduction.md","\u002Fcontent\u002Fguides\u002Fbuilding-serverless-applications-with-terraform\u002F01-introduction",{"title":57,"order":58,"authors":59,"resources":60,"time":68,"path":69,"id":70,"link":71},"2. Solution Overview",2,[9,10],[61,62,65],{"link":50,"text":51,"type":45},{"link":63,"text":64,"type":45},"https:\u002F\u002Fdocs.aws.amazon.com\u002Fcli\u002Flatest\u002Fuserguide\u002Fgetting-started-install.htm","AWS CLI",{"link":66,"text":67,"type":45},"https:\u002F\u002Fdocs.aws.amazon.com\u002Fiam\u002F","AWS IAM","3 min","02-solution-overview","02-solution-overview.md","\u002Fcontent\u002Fguides\u002Fbuilding-serverless-applications-with-terraform\u002F02-solution-overview",{"title":73,"order":74,"authors":75,"resources":77,"time":52,"path":82,"id":83,"link":84},"3. S3 buckets",3,[9,10,76],"Matt Ridehalgh",[78,79],{"link":13,"text":14,"type":15},{"link":80,"text":81,"type":15},"https:\u002F\u002Fregistry.terraform.io\u002Fproviders\u002Fhashicorp\u002Faws\u002Flatest\u002Fdocs\u002Fresources\u002Fs3_bucket","aws_s3_bucket","03-s3-buckets","03-s3-buckets.md","\u002Fcontent\u002Fguides\u002Fbuilding-serverless-applications-with-terraform\u002F03-s3-buckets",{"title":86,"order":87,"authors":88,"resources":89,"time":52,"path":100,"id":101,"link":102},"4. Lambda functions",4,[9,10],[90,91,94,97],{"link":13,"text":14,"type":15},{"link":92,"text":93,"type":15},"https:\u002F\u002Fregistry.terraform.io\u002Fproviders\u002Fhashicorp\u002Faws\u002Flatest\u002Fdocs\u002Fresources\u002Flambda_function","aws_lambda_function",{"link":95,"text":96,"type":15},"https:\u002F\u002Fdocs.aws.amazon.com\u002Fserverless-application-model\u002Flatest\u002Fdeveloperguide\u002Fterraform-support.html","AWS SAM Terraform support",{"link":98,"text":99,"type":22},"https:\u002F\u002Fgithub.com\u002Faws-samples\u002Fbuilding-serverless-applications-with-terraform\u002Fblob\u002Fmain\u002Flambdas\u002Fgreetings_lambda\u002Findex.mjs","index.mjs","04-lambda-functions","04-lambda-functions.md","\u002Fcontent\u002Fguides\u002Fbuilding-serverless-applications-with-terraform\u002F04-lambda-functions",{"title":104,"order":105,"authors":106,"resources":107,"time":52,"path":113,"id":114,"link":115},"5. API Gateway",5,[9,10],[108,109,112],{"link":13,"text":14,"type":15},{"link":110,"text":111,"type":15},"https:\u002F\u002Fregistry.terraform.io\u002Fproviders\u002Fhashicorp\u002Faws\u002Flatest\u002Fdocs\u002Fresources\u002Fapi_gateway_rest_api","aws_api_gateway_rest_api",{"link":95,"text":96,"type":15},"05-api-gateway","05-api-gateway.md","\u002Fcontent\u002Fguides\u002Fbuilding-serverless-applications-with-terraform\u002F05-api-gateway",{"title":117,"order":118,"authors":119,"resources":120,"time":52,"path":128,"id":129,"link":130},"6. Asynchronous processing",6,[9,10],[121,122,125],{"link":13,"text":14,"type":15},{"link":123,"text":124,"type":15},"https:\u002F\u002Fregistry.terraform.io\u002Fproviders\u002Fhashicorp\u002Faws\u002Flatest\u002Fdocs\u002Fresources\u002Fsqs_queue","aws_sqs_queue",{"link":126,"text":127,"type":15},"https:\u002F\u002Fregistry.terraform.io\u002Fproviders\u002Fhashicorp\u002Faws\u002Flatest\u002Fdocs\u002Fresources\u002Flambda_event_source_mapping","aws_lambda_event_source_mapping","06-async-processing","06-async-processing.md","\u002Fcontent\u002Fguides\u002Fbuilding-serverless-applications-with-terraform\u002F06-async-processing",{"title":132,"order":133,"authors":134,"resources":135,"time":149,"path":150,"id":151,"link":152},"7. Observability",7,[9,10],[136,137,140,143,146],{"link":13,"text":14,"type":15},{"link":138,"text":139,"type":15},"https:\u002F\u002Fdocs.aws.amazon.com\u002Flambda\u002Flatest\u002Fdg\u002Flambda-monitoring.html","Lambda function observability, monitoring, and troubleshooting",{"linke":141,"text":142,"type":15},"https:\u002F\u002Fdocs.aws.amazon.com\u002Fapigateway\u002Flatest\u002Fdeveloperguide\u002Frest-api-monitor.html","Monitoring API Gateway REST API",{"link":144,"text":145,"type":15},"https:\u002F\u002Fregistry.terraform.io\u002Fproviders\u002Fhashicorp\u002Faws\u002Flatest\u002Fdocs\u002Fresources\u002Fapi_gateway_account","aws_api_gateway_account",{"link":147,"text":148,"type":15},"https:\u002F\u002Fregistry.terraform.io\u002Fproviders\u002Fhashicorp\u002Faws\u002Flatest\u002Fdocs\u002Fresources\u002Fapi_gateway_stage","aws_api_gateway_stage","5 min","07-observability","07-observability.md","\u002Fcontent\u002Fguides\u002Fbuilding-serverless-applications-with-terraform\u002F07-observability",{"title":6,"order":7,"authors":154,"resources":155,"time":32,"path":159,"id":160,"link":31},[9,10],[156,157,158],{"link":13,"text":14,"type":15},{"link":17,"text":18,"type":15},{"link":20,"text":21,"type":22},"08-modularizing-your-iac-projects","08-modularizing-your-iac-projects.md",{"title":162,"order":163,"authors":164,"resources":165,"time":172,"path":173,"id":174,"link":175},"9. Summary and next steps",9,[9,10],[166,167,169,171],{"link":13,"text":14,"type":15},{"link":168,"text":51,"type":15},"https:\u002F\u002Fdeveloper.hashicorp.com\u002Fterraform",{"link":43,"text":170,"type":15},"AWS SAM",{"link":20,"text":21,"type":22},"2 min","09-summary","09-summary.md","\u002Fcontent\u002Fguides\u002Fbuilding-serverless-applications-with-terraform\u002F09-summary",{"title":177,"order":178,"authors":179,"resources":181,"time":149,"path":191,"id":192,"link":193},"10. Appendix A - Amazon EventBridge",10,[9,10,180],"Luis Cerezo",[182,185,188],{"link":183,"text":184,"type":15},"https:\u002F\u002Fregistry.terraform.io\u002Fproviders\u002Fhashicorp\u002Faws\u002Flatest\u002Fdocs\u002Fresources\u002Fcloudwatch_event_bus","aws_cloudwatch_event_bus Terraform resource",{"link":186,"text":187,"type":15},"https:\u002F\u002Fdocs.aws.amazon.com\u002Fhealth\u002Flatest\u002Fug\u002Fcloudwatch-events-health.html","Monitoring AWS Health events with Amazon EventBridge",{"link":189,"text":190,"type":15},"https:\u002F\u002Fdocs.aws.amazon.com\u002Fhealth\u002Flatest\u002Fug\u002Faws-health-planned-lifecycle-events.html#planned-lifecycle-event-notifications","Planned lifecycle events for AWS Health - What should I expect when I receive a planned lifecycle event notification?","10-appendix-A-EventBridge","10-appendix-A-EventBridge.md","\u002Fcontent\u002Fguides\u002Fbuilding-serverless-applications-with-terraform\u002F10-appendix-A-EventBridge",{"title":195,"order":196,"authors":197,"resources":198,"time":52,"path":207,"id":208,"link":209},"10. Appendix B - AWS Step Functions",11,[9,10,180],[199,202,204],{"link":200,"text":201,"type":15},"https:\u002F\u002Faws.amazon.com\u002Fblogs\u002Fdevops\u002Fbest-practices-for-writing-step-functions-terraform-projects\u002F","Best Practices for Writing Step Functions Terraform Projects",{"link":183,"text":203,"type":15},"cloudwatch_event_bus terraform resource",{"link":205,"text":206,"type":15},"https:\u002F\u002Fdocs.aws.amazon.com\u002Fstep-functions\u002Flatest\u002Fdg\u002Fconcepts-amazon-states-language.html","Amazon States Language","10-appendix-B-SFN","10-appendix-B-SFN.md","\u002Fcontent\u002Fguides\u002Fbuilding-serverless-applications-with-terraform\u002F10-appendix-B-SFN",1792578865684]