The Cloud Controls That Most Often Block Enterprise SaaS Deals
The concrete control gaps that commonly show up on enterprise security reviews, with the specific evidence buyers ask for and the engineering fix for each.
Enterprise buyers don't reject deals because of risk in the abstract. They reject them because of specific control gaps that show up in the security questionnaire and don't have evidence behind them. The procurement team has a checklist. Your answers either map cleanly to acceptable evidence or they don't.
Patterns repeat. The same handful of categories keep showing up as the sticking points in reviews I've worked through. If you fix those before the questionnaire arrives, you shorten the review cycle from weeks to days.
This is the list. Each item names the question buyers actually ask, the evidence they expect, the gap that's typically there instead, and the engineering fix.
1. Missing or unprovable MFA enforcement
Buyer asks: Is MFA enforced for all administrative access to production systems?
Acceptable evidence: An identity-provider policy export (Okta / Google Workspace / Microsoft Entra) showing MFA is required, plus a per-user enforcement status report showing every admin user is enrolled.
Common gap: MFA is "enabled" in the IdP — users can enable it — but not enforced (users must enable it). Or it's enforced for the IdP login but not for cloud-console direct access, leaving a backdoor for users who had keys before SSO was wired in. Or the policy is correct but no one can produce the export under time pressure.
Engineering fix: Switch the IdP policy from "MFA encouraged" to "MFA required." Export the policy + the per-user status report quarterly and file it. For AWS specifically, also confirm the root account has hardware MFA and that IAM Identity Center is the only path to AWS console for humans (no long-lived IAM users). For Google Cloud, confirm 2-Step Verification is enforced via Cloud Identity admin and that no service-account keys are downloadable to user laptops.
Both the policy artifact and the per-user enrollment report should live in
your evidence folder, refreshed quarterly. See
evidence-folder-template/01-access-controls/mfa-enforcement.md
in the Evidence Kit.
2. Long-lived service-account keys with no inventory
Buyer asks: How are service-account credentials managed, rotated, and inventoried?
Acceptable evidence: A CSV listing every long-lived credential (AWS IAM access key, GCP service-account JSON key, Azure service principal client secret, GitHub Personal Access Token used by automation) with owner, purpose, last-rotated date.
Common gap: A handful of keys created two years ago by engineers who have since left, with no inventory of what they're used for, who owns them, or whether they could be rotated without breaking production. Several have admin-equivalent scopes "just to make CI work."
Engineering fix: Three steps:
- Enumerate. Run a one-shot script per cloud listing every long-lived
credential. For AWS:
aws iam list-access-keysfor every user. For GCP:gcloud iam service-accounts keys listfor every service account. For GitHub:gh api orgs/<org>/personal-access-tokensfor the org. - Annotate. For each, identify the owner and purpose. Anything you can't identify, deactivate first then see what breaks. (Most of what you can't identify is genuinely orphaned.)
- Replace where possible. AWS IAM Identity Center for human access. Workload Identity Federation for GCP CI/CD. GitHub OIDC for cloud deploys. Each of these replaces a long-lived key with a short-lived token issued on demand, which is the only scalable answer.
The inventory file is the artifact buyers want. Rotation cadence is a
secondary question; for the keys that genuinely have to remain
long-lived, 90 days is the typical expectation. The CSV lives in
evidence-folder-template/01-access-controls/.
3. Audit logs not retained for the review period
Buyer asks: How long are cloud audit logs retained?
Acceptable evidence: Storage lifecycle configuration showing ≥ 365 days retention, plus a sample query against the actual log store returning the oldest available record.
Common gap: CloudTrail or Cloud Audit Logs is "enabled" but routing to a bucket with the default 90-day lifecycle. Or the bucket lifecycle says 365 days but no one ran the query to confirm logs from a year ago are actually retrievable. Or only the active log stream is retained, not the historical archive.
Engineering fix: Two artifacts:
- Storage lifecycle configuration — S3 bucket lifecycle rule, GCS bucket lifecycle rule, or Azure Storage account lifecycle policy. Configured for at least 365 days. Object-lock or bucket-lock enabled to prevent tampering.
- Coverage query — query the log store grouped by source account (or project, or subscription), confirming every prod account has logs from the start of the review period through today. Run it quarterly and save the output.
The drift you're catching with the quarterly query is the new account
that someone provisioned without adding to the org-level log sink.
Auditors specifically sample-check this. See
evidence-folder-template/02-logging-monitoring/audit-log-config.md.
4. No deploy-approval evidence
Buyer asks: How do you control changes to production?
Acceptable evidence: Branch protection rule export showing required review, plus environment protection configuration, plus a CSV of recent production deploys showing each was approved by a named reviewer.
Common gap: Branch protection is enabled but the approval evidence is the implicit "every PR has a reviewer" pattern, with no exported record. Worse — branch protection allows bypass via repo admin, and the audit log shows multiple "bypass-merged" actions.
Engineering fix: Three concrete moves:
- Lock branch protection. Require pull request reviews from CODEOWNERS, disable bypass for repository admins, require status checks to pass.
- Add Environment protection on production. GitHub Environments protection rules (or GitLab protected environments) requires explicit approval at deploy time from named approvers — this creates a per-deploy audit record automatically.
- Export the last 30 deploys quarterly. From GitHub Actions API or your CI/CD system's deploy history, dump (timestamp, commit, author, approver, environment, outcome) to a CSV. File it.
Branch protection + Environment protection together give you the prevent
side; the deploy CSV is the evidence side. Buyers ask for both. See
evidence-folder-template/03-cicd-change-management/.
5. No restore-test evidence
Buyer asks: Have you tested restoring from backup?
Acceptable evidence: Restore-test runbook plus the most recent test report — date, source backup ID, target environment, restored row counts, wall-clock recovery time, integrity-check outcome.
Common gap: Backups are configured (RDS automated backups, Cloud SQL backups, native managed-service equivalents). No one has ever restored from one. The team is implicitly trusting that the backup capability works, because the provider says it does.
Engineering fix: Run the test. Quarterly. Pick the most recent
production backup. Restore it to a non-production environment (a dedicated
restore-test project, separated from prod by IAM, ideally same region
for realistic latency). Compare row counts against the source at the
backup timestamp. Run application-level integrity checks where possible
(an app health query that exercises the schema). Record:
- Source backup ID and timestamp
- Target environment
- Wall-clock time from "click restore" to "fully restored"
- Restored row counts vs. source at backup time
- Outcome of integrity checks
- Anything that went wrong + how it was fixed
The report itself is the artifact. Even a single restore test puts you
ahead of most teams who claim "backups are working." See
evidence-folder-template/05-backups-recovery/restore-test.md.
6. Vulnerability scanning enabled but no remediation log
Buyer asks: How do you remediate critical CVEs?
Acceptable evidence: Scanner configuration (Dependabot, Renovate, Snyk, Trivy, etc.) plus a remediation log showing recent critical CVEs were closed within stated SLA.
Common gap: The scanner is enabled and producing alerts. No one is closing them on a cadence. The "SLA" exists in policy text but the operational record shows critical-severity CVEs sitting open for months.
Engineering fix: Less about tooling, more about process discipline.
- Pick a real SLA. "Critical CVEs remediated within 7 days" is defensible. "Within 24 hours" is impressive but unrealistic unless you have on-call dedicated to it. Don't write what you can't meet.
- Assign ownership. Critical CVEs assigned to a named team. New alerts trigger a ticket; tickets have a due date; the due date is tracked.
- Document the recent record. Export every critical-severity hit from the last quarter with (detected date, package, advisory ID, closed date). The CSV is the artifact.
The artifact lets you say "yes, here's the last quarter's record showing
SLA met" instead of "yes, we have a policy." Buyers can tell the
difference instantly. See
evidence-folder-template/04-vulnerability-secrets/dependency-scanning.md.
What this all has in common
Notice the pattern. In every case the control is well-known and straightforward; the gap is operational evidence that the control is being operated.
- "MFA enabled" is not the same as "MFA enforced + per-user export."
- "Backups configured" is not the same as "restored backup with row counts in a quarterly file."
- "Branch protection enabled" is not the same as "30 recent deploys exported with approver names."
- "CVE scanner running" is not the same as "remediation log showing SLA met."
The technical gap is small; the evidence gap is what blocks deals. The operational discipline of producing artifacts on cadence — quarterly export, quarterly review, quarterly file — is what separates the teams that close enterprise reviews quickly from the ones that grind through follow-up questions for a month.
If you walked this list ranking your own evidence (yes / no / "we have it but I'd have to scramble to produce it"), the to-scramble column is where the deal-cycle time leaks. Closing those is the single highest- leverage thing you can do before your next enterprise opportunity.
The full catalog
The six categories above cover the 80% case. The full Cloud Controls Evidence Kit has ~30 controls across six categories (access, logging, CI/CD, vulnerability, backups, AI workload), each with a template and refresh cadence. Browse the kit or download the ZIP.
For teams that would rather have an engineer walk their stack and produce the populated evidence folder for them, that's exactly what a Controls Review is. The output is a written report with severity, evidence requested, fix path, and effort estimate, per finding — see the sample report for what it looks like.