1.3.1.1. Resource Modules
Resource modules are designed to deploy a specific cloud platform product or service (e.g., Virtual Machines, Databases, Blob Storage buckets, etc.) and ensure that default configurations adhere to best practices, including but not limited to:
- Enabling Availability Zones
- Configuring Firewalls
- Enforcing cloud platform-recommended authentication methods
- Configuring shared interfaces such as RBAC, Resource Locks, and Private Endpoints (where supported)
These modules may include additional resources related to the primary resource; for instance, a Virtual Machine module might include disks and Network Interface Cards (NICs). However, resource modules must not deploy external dependencies of the primary resource. For example, a Virtual Machine module must not create external resources like Virtual Networks (vNets) or Subnets.
1.3.1.1.1. Use Cases
Resource modules are the backbone of modular Terraform solutions. Theoretically, users managing infrastructure with Terraform should not create corresponding resource blocks directly, but rather assemble infrastructure using resource modules extensively. Resource modules are suitable for users who need to build custom architectures compliant with WAF (Well-Architected Framework) best practices, or for users creating Pattern Modules.
1.3.1.1.2. High Cohesion
As in the Virtual Machine module example mentioned above, it would be fundamentally incorrect if a Key Vault or Virtual Network resource appeared within a Virtual Machine resource module; these resources should be managed by other resource modules. However, the presence of a Managed Disk resource within a Virtual Machine module is reasonable, as a Managed Disk is an integral component of a Virtual Machine.
A resource module should contain one primary resource and can include multiple sub-resources attached to that primary resource. For example, it can contain a Virtual Machine resource along with multiple Managed Disks and Network Interfaces.
Sometimes, multiple primary resource blocks may appear in a single resource module. For example, the AzureRM Provider has both azurerm_linux_virtual_machine and azurerm_windows_virtual_machine resources. For a Virtual Machine module, it is permissible to include both resource blocks simultaneously. However, we must configure mutually exclusive for_each or count conditions for these blocks to ensure that the resource module deploys only one of them at any given time.
1.3.1.1.3. Maximizing Configurability
Since resource modules act as resource blocks in the end-user's codebase, we should ensure as much as possible that the various attributes of the resource defined in the module can be configured via variable blocks exposed by the module. Since we cannot predict or limit how users will configure these resources, we must make every effort to ensure users can build their desired configuration combinations. Manually exposing all configurable items as variable blocks is a time-consuming and labor-intensive task; sometimes we can use certain tools to assist us.
This requires us to expose all configurable attributes of the module's primary resource and its additional resources as variables as much as possible, even if this implies that users might construct configurations that do not adhere to best practices (e.g., exposing a database to the public internet). We should allow users to configure it this way. However, while allowing users to make insecure configurations, we must ensure that the provided examples code follows best practices or, at the very least, does not contain known insecure practices. (We will discuss this topic in a subsequent chapter).
Readers can understand resource modules as modules designed to give users maximum freedom in building infrastructure. Their greatest value lies in grouping related resources together for the user in advance, while providing additional value such as data validation and simplification of best practice application that the Provider cannot offer.