For healthtech companies, one missing credential can kill a deal. Hospital systems, health plans, and enterprise partners require SOC 2 before they’ll even open a vendor security review; no report, no contract. That was the position one growth-stage healthtech company found itself in: strong product, real customer demand, but a compliance gap standing between them and their next major partnership.
The Challenge
The company had already built a working product on AWS and a growing customer base, but the software wasn’t built with compliance in mind from the start. Logging, access controls, encryption practices, and vendor management had all evolved organically to ship features fast, not to satisfy an auditor. The company was ready to go after enterprise customers, but SOC 2 kept coming up as a blocker before those conversations could even start. Without a report in hand, security reviews stalled before they began.
That left us facing a familiar problem: retrofitting compliance onto a system that was never architected for it, under real deadline pressure, without slowing down the rest of the roadmap.
The Approach
We started with a readiness assessment to see how far the gap actually was between existing practices and SOC 2’s control requirements.
Alongside a number of smaller findings, the readiness assessment surfaced seven major gaps that needed immediate attention.
- Logical access (CC6.1, Logical Access Controls): all environments (dev, staging, and production) were running in the same AWS account, with no separation between them.
- IAM hygiene (CC6.2 and CC6.3, User Access Provisioning and Least Privilege): unused users and roles had accumulated over time, and permission boundaries were not clearly defined.
- Encryption and backups (CC6.1 and A1.2, Encryption and Availability/Recovery): data was encrypted at rest, but backup recovery had never actually been tested.
- Infrastructure as Code (CC8.1, Change Management): IaC wasn’t fully automated, and the deployed infrastructure had drifted from what the IaC actually described.
- Deployment traceability (CC8.1, Change Management): it wasn’t always clear which application version was running in a given environment, pointing to gaps in the CI/CD pipeline design.
- Logging and monitoring (CC7.1 and CC7.2, System Operations): CloudTrail, AWS Config, and Security Hub weren’t fully configured across the environment.
- Evidence gathering (CC4.1, Monitoring Activities): there was no consistent process for collecting and maintaining the evidence an auditor would need to verify controls over time.
The Solutions
Once we had the full picture, we worked through each gap systematically over the following months.
Logical access
All three environments, dev, staging, and production, were originally running in a single AWS account with no real separation between them. That meant a misconfiguration or overly broad permission in one environment could bleed into another, which is exactly the kind of risk CC6.1 is meant to catch.
Full separation was the ideal end state, but migrating production out of the main account wasn’t a simple lift. Production carried the live EKS cluster, RDS instances, and everything downstream of them, and a full account migration for that ecosystem would have introduced real risk and eaten months we didn’t have against the deal timeline. So we made a pragmatic call: we moved dev and staging into their own separate accounts, which removed the bulk of the cross-contamination risk between lower environments and production, and kept production in the main account for this phase, with tighter access controls and monitoring layered on top to compensate.
This gave us meaningful isolation quickly without taking on a high-risk production migration under deadline pressure.

IAM hygiene
Access was previously managed through individual IAM users, which meant credentials to rotate, no central place to see who had access to what, and permission boundaries that had drifted over time as people joined, left, or changed roles. That’s a direct gap against CC6.2 and CC6.3, since there was no clean way to prove access was provisioned, reviewed, or revoked consistently.
We moved user management to IAM Identity Center and integrated it with Okta, which the customer was already using, so identity lived in one place instead of being duplicated across AWS. User provisioning and deprovisioning were automated through SCIM between Okta and Identity Center, so access followed a person’s actual employment status instead of relying on someone remembering to clean up an IAM user after they left.
For non-human access, like the IAM users previously used for CI/CD, we moved deployments to OIDC-based role assumption from GitHub Actions, scoped to the minimum permissions each pipeline actually needed rather than broad, long-lived credentials.
All of this, the Identity Center configuration, SCIM integration, and OIDC roles, was defined and managed through Terraform, so the access model itself became auditable and version-controlled rather than something configured by hand in the console.
Encryption and backups
Data was already encrypted at rest, which covered part of CC6.1, but backup recovery had never actually been tested, and there was no multi-region resilience story to point to. An auditor doesn’t just want to see that backups exist; they want evidence that recovery actually works and that data survives a regional failure.
We enabled multi-region backups for RDS and DynamoDB, so both the primary relational data and the NoSQL workloads had a documented recovery path outside a single AWS region. Alongside that, we set up a recurring backup recovery test on a schedule, so recovery was proven repeatedly rather than assumed to work based on the fact that a backup job ran successfully.
Infrastructure as Code
For production, rather than recreating everything from scratch and risking downtime or configuration mismatches, we imported the existing resources into Terraform state. That brought production under IaC management without touching the live environment, closing the drift gap without introducing migration risk.
For dev and staging, we built those environments using the same Terraform modules as production, parameterized through environment variables to scale resources down appropriately for lower environments. That gave us consistent, replicated infrastructure across all three environments from a single codebase, rather than separate, hand-maintained configurations that could quietly diverge from each other over time.
We automated IaC deployments to be done over pipelines with approvals.
Deployment traceability
We introduced ArgoCD and adopted GitOps practices across the pipeline, so the desired state of each environment lived in Git rather than being applied manually or inconsistently. Every image was tagged on build in GitHub using SemVer structure depending on environment, giving us a clear, immutable link between a specific commit, its build artifact, and what was actually running in an environment at any point in time.
This also gave us proper rollback: reverting to a previous state became a matter of pointing ArgoCD back to an earlier Git commit rather than manually reconstructing a past deployment. Combined, this closed the traceability gap and gave the auditor a clear, verifiable trail from code to production.

Logging and monitoring
CloudTrail, AWS Config, and Security Hub weren’t fully configured across environments, which meant limited visibility into account activity, configuration changes, and potential threats, a direct gap under CC7.1 and CC7.2 for system monitoring.
We enabled CloudTrail across all accounts for full activity logging, turned on AWS Config to track and flag configuration drift, and deployed GuardDuty for continuous threat detection. All of this fed into Security Hub, giving us a single, centralized view of findings and alerts across the environment instead of checking each service separately
Evidence gathering
We brought in Vanta to automate evidence collection continuously across AWS, GitHub, and Okta, so control evidence was captured as it happened rather than reconstructed after the fact. This gave us a real-time view of compliance status throughout the observation period and meant we walked into the audit with evidence already organized, instead of assembling it under deadline pressure.
Results and Benefits
We closed the seven major gaps and rebuilt the underlying infrastructure over the first two to three months. From there, the company entered a six-month observation period, during which monitoring, incident response, access reviews, and evidence collection ran continuously and were documented as evidence of controls operating effectively over time, not just existing on paper.
At the end of that window, the company passed its SOC 2 Type II audit, roughly nine months after the readiness assessment began. What had been a blocker standing between the company and enterprise deals became a credential that let security reviews move forward instead of stalling before they started.