A cloud infrastructure audit in three stages: set the scope, collect evidence with read-only commands, and record findings with owners.
Compliance

Cloud Infrastructure Audit Checklist: What to Check and the Evidence to Collect

A working checklist for a cloud infrastructure audit: what to check in each area, the evidence that proves it, what a pass looks like, and read-only commands to collect it. Includes a blank CSV worksheet and a mapping to SOC 2, ISO 27001, and CIS.

Reviewed for technical accuracy: November 12, 2026

  • A cloud infrastructure audit covers seven areas: inventory, identity, network exposure, data protection, logging, change management, and recovery
  • Each check needs evidence with a source, a timestamp, and a command that reproduces it
  • A finding names one resource and one owner, and is closed only when the same check passes on a fresh run
  • Run fast-changing checks daily and the full checklist quarterly, not once a year before the external audit

A cloud infrastructure audit is a structured review of what is running in your cloud accounts, who can change it, how it is exposed, and whether there is evidence to prove each answer. It covers seven areas: inventory and ownership, identity and access, network exposure, data protection, logging and monitoring, change management, and resilience and recovery.

This checklist has 29 checks across those areas. Each one states the evidence to collect and what a pass looks like, and each area comes with read-only AWS CLI commands that gather the evidence. A blank copy is available as a CSV worksheet with empty columns for scope, finding, owner, and next action.

What a cloud infrastructure audit is, and is not

An infrastructure audit answers one question for each control: is it in place, and can you show it? That makes it different from three reviews it is often confused with.

  • A security assessment or penetration test looks for ways in. An audit checks whether the controls you say you have are operating, and asks for the record.
  • A cost review looks for waste. An audit touches unused resources only because something nobody owns is something nobody is patching.
  • A compliance certification such as SOC 2 or ISO 27001 is performed by an external auditor against a framework. An internal infrastructure audit is the preparation: the same questions, asked early enough to fix the answers.

The output is not a score. It is a list of findings, each tied to a resource, an owner, and a piece of evidence, plus the evidence for every check that passed.

Before you start: scope, period, and evidence rules

Three decisions made up front prevent most of the rework later.

  1. 1Scope. List the accounts, regions, and environments under review, and state what is excluded. An account left off the list is the most common audit gap, because nobody checks what nobody listed.
  2. 2Period. Decide whether the audit is point-in-time, meaning the configuration today, or covers a period, meaning every change in the last quarter. Configuration checks are point-in-time. Change management and access reviews need a period.
  3. 3Evidence rules. Agree that every piece of evidence records its source, the time it was collected, and who collected it, and that it can be reproduced by running the same command again. A screenshot with no timestamp fails all three.

Collect evidence with a read-only role. On AWS, the managed SecurityAudit policy grants read access to security configuration without access to the data itself, and it is what most external auditors ask for.

The checklist

The commands below are for AWS and are read-only. Run them per account and per region in use, and save the output with the date. Angle brackets mark values to replace.

Inventory and ownership

An audit can only cover what is on the list, so the first question is whether the list is complete and every item has an owner.

CheckEvidence to collectWhat passing looks like
Every account, subscription, and project is in scopeOrganization account list with a named owner for each accountNo account exists outside the list, and each one has an owner who answers for it
Every resource carries an owner and an environment tagResource export with the count of untagged resourcesUntagged resources are listed, and each has a decision recorded against it
Resources are managed as code, or the exception is written downInfrastructure-as-code state compared with the live inventoryResources no code manages are known, assigned, and scheduled for import or removal
Unused resources are identifiedUnattached volumes, idle load balancers, and unassociated IP addressesEach one has an owner decision: keep, snapshot, or delete
BASH
aws organizations list-accounts --query 'Accounts[].[Id,Name,Status]' --output table
aws resource-explorer-2 search --query-string 'tag:none' --query 'Resources[].Arn'
aws ec2 describe-volumes --filters Name=status,Values=available --query 'Volumes[].[VolumeId,Size,CreateTime]' --output table

The untagged-resource search needs AWS Resource Explorer turned on with an aggregator index, and tag:none matches resources with no user-created tags. On Azure the equivalent source is an Azure Resource Graph query, and on Google Cloud it is gcloud asset search-all-resources. Whatever the source, save the export with its timestamp: the inventory is the population every later check samples from.

Identity and access

Most cloud incidents start with a credential, so auditors spend the most time on who can do what and how that access is protected.

CheckEvidence to collectWhat passing looks like
The root user has MFA and no access keysAccount summary and credential reportMFA is enabled on root, and the report shows no root access keys
People sign in through single sign-on with MFACredential report filtered to users with a console passwordNo user has a console password without MFA, and standing IAM users are the documented exception
Access keys are rotated or removedCredential report columns for key age and last useNo active key is older than the rotation policy, and unused keys are deactivated
No policy grants every action on every resource outside named admin rolesPolicy review for Action "*" with Resource "*", and privilege-escalation actionsEach administrator-level grant maps to a role with a recorded approval
Access from outside the organization is knownIAM Access Analyzer active findingsEvery external principal is expected, and unexpected findings have an owner
BASH
aws iam get-account-summary --query 'SummaryMap.[AccountMFAEnabled,AccountAccessKeysPresent]'
aws iam generate-credential-report
aws iam get-credential-report --query Content --output text | base64 -d > credential-report.csv
aws accessanalyzer list-findings --analyzer-arn <analyzer-arn> --filter '{"status":{"eq":["ACTIVE"]}}'

The credential report is a CSV with one row per user, including the root user. The columns to read are mfa_active, password_last_used, access_key_1_last_rotated, and access_key_1_last_used_date. To review one policy for wildcards and privilege-escalation actions, paste it into the free IAM policy analyzer, which runs in the browser and maps each finding to the control it affects.

Network exposure

Anything reachable from the internet should be reachable on purpose, and the audit asks for the list and the reason behind each entry.

CheckEvidence to collectWhat passing looks like
No security group opens admin or database ports to the internetSecurity group rules that allow 0.0.0.0/0 or::/0Open rules are limited to public web ports on resources meant to be public
Every internet-facing load balancer and public IP address is intendedList of internet-facing load balancers and instances with public addressesEach entry names the service it fronts and the team that owns it
Object storage is not publicly readableAccount-level and bucket-level public access block settingsAll four block settings are on at the account level, with exceptions documented per bucket
Databases are not publicly accessibleDatabase instances with the public accessibility flagNo production database has a public endpoint
BASH
aws ec2 describe-security-groups --filters Name=ip-permission.cidr,Values=0.0.0.0/0 --query 'SecurityGroups[].[GroupId,GroupName]' --output table
aws elbv2 describe-load-balancers --query 'LoadBalancers[?Scheme==`internet-facing`].[LoadBalancerName,DNSName]' --output table
aws s3control get-public-access-block --account-id <account-id>
aws rds describe-db-instances --query 'DBInstances[?PubliclyAccessible==`true`].DBInstanceIdentifier'

The security group filter returns every group with any rule open to the internet, including the ones that should be. Read the port on each rule before recording a finding: port 443 on a public load balancer is expected, port 22 or 5432 is not. Run the same commands in every region in use.

Data protection

Encryption and key handling are easy to check and easy to get wrong, which is why they appear in every framework.

CheckEvidence to collectWhat passing looks like
Volumes, databases, and buckets are encrypted at restDefault encryption setting and the list of unencrypted storesEncryption by default is on, and no production data store is unencrypted
Traffic is encrypted in transitLoad balancer listeners and their protocols and TLS policiesPublic listeners use HTTPS or TLS with a current security policy
Encryption keys rotate and their policies are scopedKey rotation status and key policies for customer-managed keysRotation is enabled, and no key policy grants use to every principal
Secrets are stored in a secrets manager, not in code or stateSecret-scanning results for repositories and a review of state filesNo live credential appears in a repository, variable file, or plain-text state
BASH
aws ec2 get-ebs-encryption-by-default
aws rds describe-db-instances --query 'DBInstances[?StorageEncrypted==`false`].DBInstanceIdentifier'
aws elbv2 describe-listeners --load-balancer-arn <load-balancer-arn> --query 'Listeners[].[Port,Protocol,SslPolicy]' --output table
aws kms get-key-rotation-status --key-id <key-id>

Encryption by default only applies to volumes created after it was switched on, so an account can have the setting enabled and still hold older unencrypted volumes. Check the stores themselves, not only the setting. For secrets, keeping them out of Terraform state is its own review.

Logging and monitoring

Without a complete audit trail none of the other answers can be verified, so the trail itself is audited.

CheckEvidence to collectWhat passing looks like
An audit trail records API activity in every regionTrail configuration: multi-region flag, log file validation, destinationA multi-region trail with validation on writes to storage the workload accounts cannot alter
Logs are kept for as long as policy requiresRetention setting on each log group and log bucketNo log group is set to never expire by accident, and retention matches the written policy
Alerts exist for high-risk events and reach a personAlarm list for root sign-in, IAM changes, and network rule changes, with the route each one takesEach alert has an owner, and a test alert was acknowledged within the audit period
Threat detection is turned on in every region in useDetector status per regionA detector is enabled wherever resources run, and findings have an owner
BASH
aws cloudtrail describe-trails --query 'trailList[].[Name,IsMultiRegionTrail,LogFileValidationEnabled]' --output table
aws logs describe-log-groups --query 'logGroups[?!retentionInDays].logGroupName'
aws guardduty list-detectors

A trail that writes to a bucket in the same account can be altered by anyone who compromises that account. Auditors look for log storage in a separate account with validation turned on, so the trail can be trusted as evidence for every other area on this list.

Change management

Auditors sample changes and ask for the request, the review, and the approval behind each one.

CheckEvidence to collectWhat passing looks like
Production changes go through a reviewed pull request and a planA sample of changes, each with its pull request, plan output, and approverEvery sampled change has a reviewer who is not the author
Live infrastructure matches the codeResult of a scheduled drift check for each production workspaceThe latest check shows no drift, or each difference has a ticket
Console changes in production are detectedAudit trail query for write events from console sessionsConsole writes are rare, and each one links to an incident or an approved exception
Emergency changes are recorded and reconciled into codeBreak-glass log with the follow-up change for each useEvery emergency change was reviewed afterwards and the code was updated to match
BASH
terraform plan -detailed-exitcode -input=false -lock=false
aws cloudtrail lookup-events --lookup-attributes AttributeKey=ReadOnly,AttributeValue=false --max-results 50 --query 'Events[].[EventTime,Username,EventName]' --output table

The drift check exits with code 2 when live infrastructure differs from the code, which makes it easy to schedule; Terraform drift detection covers the setup. lookup-events returns management events from the last 90 days. Console activity is marked by sessionCredentialFromConsole in each event record, so filter the output on that field to separate console writes from pipeline writes.

Resilience and recovery

A backup that has never been restored is an assumption, and the audit asks for the restore test, not the backup setting.

CheckEvidence to collectWhat passing looks like
Every stateful resource is backed upBackup coverage report with retention period per resourceNo production database or volume is missing from a backup plan
A restore was tested during the audit periodRestore test record with the date, the duration, and who ran itThe restore completed inside the recovery time objective
Production databases survive the loss of one zoneMulti-zone setting for each production databaseSingle-zone production databases are listed with an accepted-risk decision
Production data stores have deletion protectionDeletion protection flag for databases and versioning for bucketsProtection is on, and turning it off requires a reviewed change
BASH
aws rds describe-db-instances --query 'DBInstances[].[DBInstanceIdentifier,MultiAZ,BackupRetentionPeriod,DeletionProtection]' --output table
aws backup list-protected-resources --query 'Results[].[ResourceArn,LastBackupTime]' --output table

Retention settings prove that backups are configured. Only a restore proves that they work. Record the restore test like any other evidence: the date, the resource restored, how long it took, and who ran it.

How the areas map to SOC 2, ISO 27001, and CIS

The same evidence usually satisfies more than one framework, so it is worth collecting once and referencing many times. This table shows where each area most often lands.

AreaSOC 2ISO 27001:2022CIS AWS Foundations section
Inventory and ownershipCC6.1A.5.9Not covered
Identity and accessCC6.1, CC6.2, CC6.3A.5.15, A.5.18, A.8.2Identity and Access Management
Network exposureCC6.6A.8.20, A.8.22Networking
Data protectionCC6.1, CC6.7A.8.24Storage
Logging and monitoringCC7.2A.8.15, A.8.16Logging, Monitoring
Change managementCC8.1A.8.9, A.8.32Not covered
Resilience and recoveryA1.2A.8.13, A.8.14Not covered

Treat the mapping as orientation. Your auditor decides which evidence satisfies which control, and frameworks are scoped differently for every organization. The CIS AWS Foundations Benchmark is a configuration baseline, so it has nothing to say about ownership, change approval, or restore testing.

Recording findings so they survive the audit

A finding that says "some security groups are too open" cannot be assigned, fixed, or verified. A usable finding names one resource and carries its own evidence. The worksheet columns exist to force that. Here is one illustrative row filled in, using a made-up resource:

ColumnExample entry
AreaNetwork exposure
CheckNo security group opens admin or database ports to the internet
ScopeProduction account, us-east-1
Evidence referencedescribe-security-groups output, 12 November 2026 09:14 UTC, saved as evidence/network/sg-open.json
Findingsg-0a1b2c3d allows 0.0.0.0/0 on port 22 and is attached to two instances
OwnerPlatform team
Next actionRemove the rule through a reviewed change and use Session Manager for access
Verified atEmpty until a fresh run of the same command shows the rule is gone

The last column is the one audits most often skip. A finding is closed when the same check, run again, passes, and the new output is saved next to the old one. Marking it done in a ticket is not verification.

How often to run it

Running all checks once a year, the week before an external audit, is how teams end up with a long list and no time. Splitting the checklist by how fast each area changes keeps the workload flat:

  • Continuously or daily: drift between code and live infrastructure, new public exposure, and root user activity. These change without warning and are cheap to check automatically.
  • Monthly: access key age, unused credentials, untagged resources, and unused resources.
  • Quarterly: the full checklist, a sample of changes for the change management review, and a restore test.

Where automation helps

Every check above can be run by hand, and for a first audit it is worth doing so, because it shows where the evidence lives. The cost appears on the second and third pass, when the same exports have to be collected again and reconciled against the previous round.

ops0 records deployments, policy checks, compliance scans, and approvals as infrastructure changes, so the evidence for the change management and configuration areas already exists when the audit starts. Infrastructure audit in ops0 turns that history into point-in-time reports that can be shared with an auditor through a password-protected link, and audit packs bundle evidence for a chosen period. The checklist stays the same. What changes is that the evidence is collected as the work happens.

Quick answers

What is a cloud infrastructure audit?

A cloud infrastructure audit is a structured review of what is running in your cloud accounts, who can change it, how it is exposed, and whether evidence exists to prove each answer. It checks that controls are in place and operating, and it produces a list of findings with owners plus the evidence for every check that passed.

What should a cloud infrastructure audit checklist include?

Seven areas: inventory and ownership, identity and access, network exposure, data protection, logging and monitoring, change management, and resilience and recovery. For each check, the checklist should state the evidence to collect and what a pass looks like, so two reviewers reach the same answer.

What access does an auditor need to a cloud account?

Read-only access to configuration, not to data. On AWS the managed SecurityAudit policy is the usual choice: it can read IAM, network, logging, and encryption settings without reading the contents of buckets or databases. Many teams avoid granting access at all by sharing exported evidence or point-in-time reports.

How is an infrastructure audit different from a security assessment?

A security assessment or penetration test looks for weaknesses an attacker could use. An audit checks whether the controls you have defined are in place and asks for proof. The two overlap on findings such as open ports, but an audit also covers ownership, change approval, and restore testing, which an assessment does not.

How long does a cloud infrastructure audit take?

The evidence-collection commands in this checklist run in minutes per account. The time goes into reviewing the output, agreeing an owner for each finding, and fixing what was found, which grows with the number of accounts in scope and how much evidence already exists.

How often should cloud infrastructure be audited?

Split the checklist by how fast each area changes. Check drift, public exposure, and root activity continuously; check access keys and untagged resources monthly; and run the full checklist with a restore test each quarter. A single annual audit leaves most of the year unchecked.

Sources
From article to workflow

Turn infrastructure context into a reviewed change.

Review generated infrastructure code with policy checks, cost context, approval, and audit evidence before deployment.

Related articles

All articles