Photo by Vitaly Gariev on Unsplash
Getting a development environment shouldn't require a ticket, a wait, or a working knowledge of cloud consoles. This is the story of how we replaced a manual, bottlenecked provisioning process with a secure, automated self-service platform and then made it accessible to every developer through AI.
The Problem
We were mid-migration moving a suite of services from Windows to Linux, and suddenly every developer started requesting a Linux machine to build and test their work. The initial approach was simple - someone from the infrastructure team would spin up an EC2 instance on request.
It worked, until it didn't.
Requests grew faster than capacity, machines sat idle burning cost, and there were no guardrails in sight. The process was manual, inconsistent and unsustainable.
Solution: Self-Serve Portal
We agreed to use AWS Service Catalog to replace the manual process. Think of it as an internal app store for cloud infrastructure where teams publish approved, governed resources that end users can deploy on demand with no ad hoc provisioning, no compliance surprises.
This gave developers the ability to launch their own Linux environment on demand, within a set of smart, automated guardrails.
Governance
It started with governance. We added a hard limit of one instance per user. User identity was pulled from SSO metadata to correctly tag every resource with its respective owner. This was achieved using a custom resource as the very first step.
Golden AMI
AWS Image Builder allowed us to ship every machine with tools required for engineers such as AWS CLI, Terraform, Rootless Docker, etc. This pipeline was scheduled to trigger every week but only if a new base AMI version is available or a new reciepe is released. This allowed us to maintain zero-drift environment that is always up to date without any manual intervention.
Lifecycle Management
Avoiding spending on idle machines and optimising patching process was the next challenge we took on.
Idle compute was solved by creating two Event Bridge schedules: one runs every day to stop instances at 7pm, and another to start the instance at 8am. We even baked in a script that lets developers opt out of the daily shutdown on an ad-hoc basis.
To optimise the patching, we created one more schedule that triggers a lambda biweekly, responsible for refreshing the instance and notifying user but only if a new golden AMI version is available.
Persistent Storage
We didn’t want users to lose their data every 2 weeks so had to find a way to persist it across instance refreshes.
Initially, to persist user data across instance refresh we mounted S3 to user’s home directory utilising S3 Files, however that proved to be very slow and made us switch to EBS in just a weeks time.
To ensure the EBS data volume is created in the same AZ as instance or an existing data volume is used if available, another custom resource was implemented before the data volume could be attached.
Additionally, to allow developers to share files among each other we allowed read-write to a shared bucket.
Security
Both Service Catalog Product role and IAM role assigned to the user were associated with least privilege policies. User would only have access to launch the product and all actions required to launch the developer resources were associated with Service Catalog Product role.
Authentication to developer machine was controlled with corporate AD by utilising AWS AD Connector. Sudo access was blocked on all developer machines and rootless Docker ensures containers can be run without elevated privileges.
Harnessing the power of AI
Automating the entire process was a big win but improving experience for users that are not familiar with AWS was the next frontier. We built an AI skill that lets developers request a Linux instance using plain natural language. This AI skill comprises of a SKILL.md file along with a python script that interacts with AWS using boto3. Instead of navigating the AWS Service Catalog UI, a developer can simply say:
Can I get a Linux dev machine?
The skill handles the rest:
Checks if any inputs are missing and prompts if needed.
It validates whether an instance already exists, then either surfaces it or provisions a new one.
Business Impact
Zero wait time: developers get an environment the moment they need it, no tickets, no queues
Cost optimised: automated lifecycle management eliminates idle compute spend.
Consistent & secure: every machine starts from a hardened golden AMI with no configuration drift.
AI-accessible: non-cloud-native developers can request environments in plain English, no console required.