linuxlab.io
Tutorials▾
  • Linux & networking
    File system, processes, TCP/IP, BGP and OSPF
    →
  • Terraform & IaC
    HCL, state, plan/apply on a LocalStack sandbox
    →
  • Git & GitHub
    Object model, plumbing, branching, GitHub Actions
    →
All tutorials →
PricingAboutSign inCreate account
/
Intro
Lessons
Footer
linuxlab-TutorialsPricingAboutPrivacy & cookies
Copyright © 2026 LinuxLab. All rights reserved.
linuxlab.io
Tutorials▾
  • Linux & networking
    File system, processes, TCP/IP, BGP and OSPF
    →
  • Terraform & IaC
    HCL, state, plan/apply on a LocalStack sandbox
    →
  • Git & GitHub
    Object model, plumbing, branching, GitHub Actions
    →
All tutorials →
PricingAboutSign inCreate account
/
  • Введение
  • Уроки
  • How it works
  • База знаний
  • Шпаргалка
  • Capstone
  • Собеседование
home/terraform/lessons/tf-intermediate-02-module-from-registry

lesson ── terraform-intermediate ── ~15 мин ── 5 шагов

A Module from the Terraform Registry

The community has written modules for almost everything: VPC, EKS, ALB, S3 with audit configuration. Before you write your own, look at the Registry. Often a ready-made module covers 90% of what you need and saves you a week.

Here you will wire up terraform-aws-modules/s3-bucket/aws from the Registry, a public module maintained by an active community. You will see how to read version constraints, how to find inputs and outputs in the documentation, and how to pin a version.

▶ интерактивный sandbox

Поднимется пара контейнеров: terraform 1.9 и localstack 3.8 в одной сети. В браузере откроется терминал, можно сразу terraform init. Каждый шаг проверяется автоматически. TTL 45 минут, без регистрации.

запустить sandbox →

stack ── terraform · localstack · 1 GB RAM · самоуничтожается через 45 мин простоя

Шаги

  1. 01

    Read the module documentation

    We will wire up terraform-aws-modules/s3-bucket/aws. This is the most popular community module for S3.

    Documentation: https://registry.terraform.io/modules/terraform-aws-modules/s3-bucket/aws/latest

    In real work you need to read these sections:

    • Inputs, which variables it accepts.
    • Outputs, which values it returns.
    • Examples, ready-made usage samples.
    • Provider Versions, which version of the AWS provider it needs.
    • CHANGELOG.md in the git repo, what changed in past versions.

    This is the first thing you do before using any community module. You don't write HCL, you don't debug errors, you read.

    For now we do nothing, we just understand the process.

    ✓ Ready to wire it up.

  2. 02

    Wire up the module with a pinned version

    Create main.tf:

    hcl
    resource "random_id" "suffix" {
      byte_length = 4
    }
    module "logs_bucket" {
      source  = "terraform-aws-modules/s3-bucket/aws"
      version = "~> 4.0"
      bucket = "linuxlab-registry-logs-${random_id.suffix.hex}"
      versioning = {
        enabled = true
      }
      tags = {
        Owner   = "student"
        Project = "registry-lesson"
      }
    }
    output "registry_bucket_arn" {
      value = module.logs_bucket.s3_bucket_arn
    }

    What matters:

    • source, three segments namespace/name/provider, no https://.
    • version = "~> 4.0", a pessimistic constraint, see tf-module-versioning. Takes any 4.x, but not 5.x.
    • bucket, versioning, tags, the module inputs. Their names and format come from its documentation, they are not invented.
    • module.logs_bucket.s3_bucket_arn, the module output. Again, the name is not invented, it comes from the module's Outputs section.

    ✓ The wiring is described. Now init.

  3. 03

    init: download the module and submodules

    bash
    cd /home/student/tf-registry
    terraform init

    Internet access is needed only for the Terraform Registry, the module's own HCL will go to LocalStack endpoints, not to real AWS.

    The output should contain:

    Initializing modules...
    Downloading registry.terraform.io/terraform-aws-modules/s3-bucket/aws ...

    Check what got downloaded:

    bash
    cat .terraform/modules/modules.json | jq '.Modules[] | {Key, Source, Version}'

    You will see the main module and its submodules (large community modules use other modules internally). It is normal that you called one, while .terraform/modules/ may end up with 5 directories.

    подсказка

    If init fails with a network error: check internet with `curl -I https://registry.terraform.io`. In our sandbox this should work (links.internal: false).

    ✓ The module is downloaded. Now plan and apply.

  4. 04

    Apply: the module creates the bucket

    bash
    terraform apply -auto-approve

    The module's plugins see the AWS endpoints configured in provider.tf (we inherited them from aws-localstack-provider.tf). Inside the module there is no special setup, just aws_s3_bucket. So it works both on LocalStack and on real AWS.

    After apply, look at the state:

    bash
    terraform state list | grep module

    The addresses inside the module may look like this:

    module.logs_bucket.aws_s3_bucket.this[0]
    module.logs_bucket.aws_s3_bucket_versioning.this[0]

    Note the [0], the community module uses count = local.create ? 1 : 0 internally (optional creation). This is a common pattern in large modules.

    ✓ The Registry module created the bucket inside its own nesting.

    The same thing on OpenTofu

    OpenTofu keeps its CLI and state compatible with Terraform for the commands in this step: migration usually goes through mv .terraform .terraform.bak; tofu init -upgrade. But on the first switch make a backup of state and run on a feature branch, the differences cluster in newer features (variables in backend, state encryption, OCI registry-backed modules). See tf-opentofu-parity for the full matrix.

    • → OpenTofu parity
  5. 05

    Read the module output

    bash
    terraform output registry_bucket_arn

    It should print the bucket ARN (arn:aws:s3:::linuxlab-registry-logs-...).

    This value passed through two contracts:

    • The module declared output "s3_bucket_arn" { value = ... }.
    • The root declared output "registry_bucket_arn" { value = module.logs_bucket.s3_bucket_arn }.

    Without an explicit output at the root level, nothing is plainly visible outside the root. A module output is available only through the address module.X.<name>, but terraform output shows only root-level outputs.

    ✓ The contract closed: module to root to CLI.

    When not to use a Registry module

    A ready-made module saves time, but it is not always the right choice:

    • You don't need 90% of the inputs. terraform-aws-modules/vpc/aws has 200+ variables. If you use 5, your HCL looks deceptively simple, but the dependency tree holds a pile of code you do not know. Debugging gets harder.

    • "Magic" behavior. A good community module documents its behavior, but not always, you run into modules with non-obvious dependencies (for example, they create an IAM role automatically).

    • Versions and upgrade pain. A major upgrade (4.x to 5.x) usually breaks the contract. If 50 of your roots use the module, the upgrade is a sprint of work.

    • Your 100-line module vs a 5000-line Registry one. If your needs are simple, your own module is better. Full control, a clear dependency graph.

    Rule: a community module when the ecosystem is behind you. Large AWS infra, ALB+EKS+RDS, take the community one. Small project, often simpler to write your own.

    • → Module sources
    • → Module versioning

Что ты узнал

A Registry module = a source of the form <namespace>/<name>/<provider> plus a required version. Without version, Terraform takes the max, which in production is a time bomb. The module documentation lives on its Registry page, the Inputs and Outputs sections, and that is its contract.

команды

  • terraform initdownloads the module and its submodules into .terraform/modules/
  • terraform init -upgraderereads version constraints and downloads newer ones within their bounds
  • terraform providersthe provider tree by module: shows which submodules got pulled in

концепции

  • · Registry module = <namespace>/<name>/<provider> + a required version
  • · version constraint is required: otherwise a minor update breaks production
  • · Module documentation: on the Registry page, read it before use

← предыдущий

Troubleshooting Garden: state and the cloud have drifted apart

следующий →

pre-commit hooks for Terraform

Footer
linuxlab-
Copyright © 2026 LinuxLab. All rights reserved.
Tutorials
Pricing
About
Privacy & cookies