I just finished my first ever infrastructure project for a client. My Terraform skills are good enough to be dangerous, but during the development of this project I learned a lot that I would do differently next time.

Project structure

Having worked with semi-professional Terraform code before, I applied what I knew to my new project. That was mainly that we have a shared base and an overlay directory for each environment. I went with a single Terraform module for the shared infrastructure, and variables for each environment. Naively, roughly every service had their own file.

.
├── modules
│   └── infrastructure
│       ├── alb.tf
│       ├── cache.tf
│       ├── database.tf
│       ├── dns.tf
│       ├── ecr.tf
│       ├── ecs.tf
│       ├── iam.tf
│       ├── logs.tf
│       ├── main.tf
│       ├── network.tf
│       ├── secrets.tf
│       ├── security.tf
│       ├── ssl.tf
│       ├── state.tf
│       └── variables.tf
├── production
│   ├── main.tf
│   └── secrets.tf
└── staging
    ├── main.tf
    └── secrets.tf

This works very well, but I already started running into issues extending this setup. For my next project, I would probably find individual components and turn them into smaller reusable submodules. If I were to rewrite the project above, I would probably structure it like this (not a complete project, but I think you get the idea):

.
├── modules
│   └── infrastructure
│       ├── main.tf
│       ├── modules
│       │   ├── database
│       │   │   ├── iam.tf
│       │   │   ├── logs.tf
│       │   │   ├── main.tf
│       │   │   ├── outputs.tf
│       │   │   ├── rds.tf
│       │   │   └── variables.tf
│       │   ├── loadbalancer
│       │   │   ├── alb.tf
│       │   │   ├── logs.tf
│       │   │   ├── main.tf
│       │   │   ├── outputs.tf
│       │   │   └── variables.tf
│       │   ├── network
│       │   │   ├── dns.tf
│       │   │   ├── logs.tf
│       │   │   ├── main.tf
│       │   │   ├── outputs.tf
│       │   │   ├── ssl.tf
│       │   │   ├── variables.tf
│       │   │   └── vpc.tf
│       │   ├── service
│       │   │   ├── ecr.tf
│       │   │   ├── ecs.tf
│       │   │   ├── iam.tf
│       │   │   ├── logs.tf
│       │   │   ├── main.tf
│       │   │   ├── outputs.tf
│       │   │   └── variables.tf
│       │   └── state
│       │       ├── locks.tf
│       │       ├── main.tf
│       │       ├── outputs.tf
│       │       ├── s3.tf
│       │       └── variables.tf
│       ├── main.tf
│       ├── outputs.tf
│       └── variables.tf
├── production
│   ├── main.tf
│   └── secrets.tf
└── staging
    ├── main.tf
    └── secrets.tf

Secrets

I decided to use git-crypt to manage secrets, but that was only before I learned about SOPS. It's too late to migrate now, but if I could, I would choose SOPS for secrets any day of the week for upcoming projects. It even has a Terraform provider, so there's no excuse not to use it. ;)

Conclusion

Overall I'm pretty happy with how the project turned out, but there are some things that I learned during this project that will pay off later.


This is post 057 of #100DaysToOffload.


Continue Reading