Automatic client provisioning
Fully automated client onboarding, in the hands of the people who operate your platform, with no code written and no wait on a platform team.
By: Benjamin Clark
Intent
This pattern is a specialised implementation of dynamic Terraform on demand, which is itself a child of data-driven Terraform. It assumes a multi-tenant SaaS platform that stores each client in a mutable record, as in config as data. It fully automates client onboarding: when an operator adds a client, provisioning runs by itself, shifting the work left from DevOps and platform teams to the people who operate the platform. This enables three outcomes:
- A new client can be onboarded as quickly as the platform can provision it, with no code written.
- Operators onboard clients themselves, rather than raising a request with a DevOps or platform team.
- Every client is set up the same way, and a provisioning job changes only the client it was started for.
Motivation
On most multi-tenant platforms, onboarding a client is an engineering task: an operator raises a request, and a DevOps or platform engineer adds the client to the code and deploys it. That fails in three ways:
- The engineering backlog sets the pace. A client who has signed can't start until an engineer is free, however simple their setup.
- Specialists become a queue. Every new client takes a DevOps or platform engineer away from improving the platform itself.
- Manual setup varies. Clients set up by hand, repo by repo, end up different from each other, and nobody can say for certain whether one is complete.
This pattern applies the shift Team Topologies describes, where platform teams provide services that others use without waiting on them. Engineers build the provisioning once, and operators use it, so adding a client becomes routine, business-as-usual work. Terraform then derives what that client needs from the record, one client at a time and from released code only. A failed run goes to a person, and can safely be sent again.
Applicability
Use this pattern when:
- You onboard clients often, and each needs its own infrastructure.
- The people who operate the platform, rather than engineers, should be able to bring a client on.
- Client details live in a mutable record, outside the repos that manage the Terraform, as in dynamic Terraform on demand.
Do not use this pattern when:
- Clients are few and rarely change, where editing the data in the repo and deploying is simpler.
- Each client's infrastructure is costly or risky enough to need a person to review its plan.
Structure
Participants
| Participant | Role |
|---|---|
| Operator | Runs the platform day to day, adds or changes a client with no code written, and sees progress on the client's record. |
| Admin API | Validates the change, saves the record, and requests provisioning for that client. |
| Client record | Holds the client's settings, keyed on an immutable reference, and shows how provisioning is going. |
| Provisioning queue | Hands over one request at a time, in order. It can be any message queue that keeps requests in order, such as a first-in, first-out queue in Amazon SQS. |
| Orchestrator | Sets a mutex so that only one run happens at a time, runs the latest release of each repo's deploy for that client, and reports the outcome. |
| Deploy workflow | Reads the client's record as Terraform's input, and applies Terraform to that client's resources only. |
Constraints and trade-offs
- Reviewing the code no longer tells you everything, because what a deploy builds depends on data that changes without a pull request. Operators' changes need validation of their own, as in config as data, and a record of who changed what, as in immutable audit trail.
- Applying one client at a time relies on targeted applies, which HashiCorp advises against using routinely, so full deploys still need to bring every client back in line at each release.
- Runs happen one at a time, so that applies can't conflict. A large batch of new clients takes as long as all of its runs added together.
- Engineers still own the machinery: one queue, mutex and orchestrator for the whole platform, and a provisioning mode in each repo's deploy workflow. When a run fails, an engineer still has to find the cause and fix it before the run is sent again.
Part of how I deliver
This is how I take client onboarding off the engineering backlog, and hand it to the people who operate your platform. It's one of many patterns I bring through contract delivery, and it builds on the Terraform you already run.
Is every new client a project?
I build multi-tenant platforms where adding a client is routine, and each client's data stays its own. If you're building one, or yours has become hard to scale, book a call and we'll talk it through.
