Hardware FixRecommendedDevice not working? Your driver may be the problemCheck updates for common hardware issues.Fix DriversOctober DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsSlow PC?RecommendedPC slow today? Run a repair scan before it gets worseResolve common Windows issues and optimize system performance.Scan Now×
Skip to content
World desk11 min

How to Test Ansible Deployments with Chef InSpec and Test Kitchen

Use Test Kitchen to create isolated targets, Ansible to converge them, and Chef InSpec to verify packages, services, ports, files, users, and application behavior. This guide covers setup, controls, lifecycle commands, multi-platform testing, idempotence, CI artifacts, and failure diagnosis.
Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The reliable pattern is simple: let Test Kitchen create an isolated machine, let Ansible converge your playbook or role on it, and let Chef InSpec verify the machine against the deployment contract. The kitchen-inspec verifier connects those stages. You can run one target with kitchen verify or execute the complete create, converge, setup, verify, and destroy lifecycle with kitchen test.

What this testing stack does

Each tool has a distinct responsibility, so failures are easier to diagnose when the boundaries stay clear.

As an Amazon Associate I earn from qualifying purchases.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Ansible applies the change

Your playbook or role is the system under test. It installs packages, writes configuration, creates users, enables services, opens or closes ports, and performs any other deployment work. Ansible should be responsible for changing the target, not for declaring that the resulting machine is correct.

Test Kitchen supplies repeatable targets

Test Kitchen is a harness for executing infrastructure code on one or more platforms in isolation. Its configuration is organized around four units:

  • Driver: creates and removes a target, such as a container, virtual machine, or cloud instance.
  • Provisioner: runs Ansible against that target.
  • Platform: identifies the operating-system image or other target definition.
  • Suite: groups the playbook inputs and verification profile for a scenario.

A Kitchen instance is the combination of a suite and a platform. That makes it possible to test the same role against several operating systems without changing the test contract.

kitchen-inspec connects verification

The kitchen-inspec plugin allows Kitchen to run Chef InSpec after convergence. Set verifier: name: inspec in kitchen.yml. The verifier can use Kitchen’s host and port information automatically, or you can provide explicit connection settings when the target requires them.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

InSpec describes the expected state

Chef InSpec expresses compliance, security, and policy expectations in a human- and machine-readable language. It can evaluate the local machine or connect to a remote host over SSH. Its resources let you test packages, services, ports, files, users, ownership, permissions, configuration values, and application responses without coupling the test to the Ansible task names that produced them.

Start with a deployment contract

Before writing YAML or controls, list what a successful deployment must make true. These are observable outcomes, not implementation details.

Record required packages

Specify each package and, when it matters, the expected version or version range. A test that only checks for a package name can pass while an incompatible version is installed.

Define service behavior

For every daemon, decide whether it must be installed, enabled at boot, running now, and listening on a particular address or port. Treat those as separate requirements where they have different failure modes.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Specify files and permissions

Identify configuration and data paths, required content, owner, group, and mode. A file with correct text but world-writable permissions is not a successful deployment.

Define accounts and access

Document service users, shells, supplementary groups, home directories, and ownership of application files. If the account must not permit interactive login, make that an explicit assertion.

Test externally visible behavior

Where possible, verify an endpoint’s status code, response header, or other stable contract. An HTTP check catches failures that package and process checks miss, such as a broken listener, invalid configuration, or an application that starts but cannot serve requests.

Keep idempotence separate

Final-state controls answer “is the machine correct?” Idempotence answers “does a second run leave it unchanged?” Run the playbook twice and inspect the second run’s changes separately from InSpec verification. Mixing both questions into one control makes a failure ambiguous.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Create the Kitchen project

Install compatible versions of Test Kitchen, the Ansible provisioner, the driver you intend to use, and the kitchen-inspec verifier. Pin those dependencies in the project and run the same versions in CI so a plugin upgrade does not silently change the test environment.

Use a clear directory layout

A small role-oriented project can look like this:

.
├── kitchen.yml
├── converge.yml
├── roles/
│ └── webapp/
│ ├── tasks/
│ ├── templates/
│ └── defaults/
└── test/
└── integration/
└── default/
└── controls/
└── webapp.rb

The default kitchen-inspec convention is test/integration/%suite%. A suite can override that location with inspec_tests. Keeping controls next to the suite makes it obvious which contract belongs to which scenario.

Configure a minimal instance

This configuration shows the essential shape. The exact driver options depend on the driver plugin and your target environment.

provisioner:
name: ansible

driver:
name: docker

platforms:
- name: ubuntu

verifier:
name: inspec

suites:
- name: default
provisioner:
playbook: converge.yml
verifier:
inspec_tests:
- test/integration/default

The driver creates an isolated Ubuntu target, the Ansible provisioner runs converge.yml, and the InSpec verifier reads controls below test/integration/default. Replace the driver and platform with the operating systems and images your deployment supports.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Make inventory and variables explicit

Do not hide test inputs in a developer’s shell profile. Put role variables in suite or playbook configuration, identify the inventory used for the Kitchen instance, and record secrets through the CI secret mechanism rather than committing them. Explicit inputs let you tell whether a failure came from inventory, variable precedence, provisioning, or verification.

Write InSpec controls around outcomes

Controls should prove the contract while remaining independent of task ordering. The following example checks a web deployment without assuming which Ansible module created each resource.

control 'webapp-package' do
impact 1.0
title 'Web server package is installed'

describe package('nginx') do
it { should be_installed }
end
end

control 'webapp-service' do
impact 1.0
title 'Web server is enabled and running'

describe service('nginx') do
it { should be_enabled }
it { should be_running }
end
end

control 'webapp-listener' do
impact 1.0
title 'Only the intended HTTP service listens on port 80'

describe port(80) do
it { should be_listening }
its('processes') { should include 'nginx' }
end
end

control 'webapp-config' do
impact 1.0
title 'Configuration has the required ownership and mode'

describe file('/etc/nginx/nginx.conf') do
it { should exist }
its('owner') { should eq 'root' }
its('group') { should eq 'root' }
its('mode') { should cmp '0644' }
its('content') { should match /worker_processes/ }
end
end

control 'webapp-account' do
impact 1.0
title 'The service account has the intended login policy'

describe user('www-data') do
it { should exist }
end
end

Use stable assertions. Matching an exact generated timestamp or a temporary path creates brittle tests. If a value is security-sensitive, assert the precise value and permissions; if it is implementation-specific, test the behavior that matters instead.

Check application responses

For a service reachable from the verifier, add an HTTP contract that reflects the supported interface. For example, assert that the endpoint returns the expected status and a required header. Keep network assumptions explicit: a container-only test may use the container’s interface, while an SSH-based test may need a routable address and port forwarded by the driver.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Control severity deliberately

InSpec impact values communicate the consequence of a failure. Mark a missing security control or unavailable production endpoint as high impact, and use lower impact for advisory hardening checks. The value does not change whether a control runs, but it helps CI and compliance consumers prioritize failures.

Run the Kitchen lifecycle

Kitchen’s documented lifecycle is create, converge, setup, verify, and destroy. Running each phase separately is useful while developing controls; running kitchen test is convenient for a clean, disposable check.

Create an isolated target

kitchen create default-ubuntu

Kitchen asks the configured driver to create the target for the selected suite and platform. If this fails, inspect the driver, image name, runtime permissions, network access, and local resource limits. An InSpec control cannot diagnose a target that never started.

Converge with Ansible

kitchen converge default-ubuntu

This runs the configured playbook against the Kitchen instance. Provisioning errors belong here: syntax failures, missing variables, unreachable repositories, failed package installation, and task errors should be fixed before interpreting verification results.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Run setup when required

kitchen setup default-ubuntu

The setup phase prepares the target for verification, including any transport or verifier prerequisites required by the configured plugins. If setup fails, check SSH credentials, the remote user, privilege escalation, and whether the image contains the expected shell and package manager.

Verify the machine

kitchen verify default-ubuntu

The verifier executes the InSpec profile and reports each control as passed or failed. Read the resource output rather than treating the final exit code as the diagnosis. A failed service control may be caused by a package failure, a disabled unit, a bad configuration, or a process that crashed after starting.

Destroy the instance

kitchen destroy default-ubuntu

Destroy ephemeral targets after a run, especially in CI. Leaving instances behind can consume storage, addresses, and credentials and can make a later run appear to pass because it reused stale state.

Run the complete flow

kitchen test default-ubuntu

This command executes the create, converge, setup, verify, and destroy sequence for the instance. During debugging, use the individual commands so you can preserve a failed machine for inspection. Once the test is stable, the complete flow gives CI a clean start and deterministic cleanup.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Test more than one platform

A role that passes on one image may fail elsewhere because package names, service managers, filesystem locations, default users, or security policies differ. Add platforms that represent the supported deployment boundary rather than every image you can find.

Decision axis Questions to answer
Isolation Does the driver provide a clean target for every run, or can state leak between tests?
Operating-system fidelity Does the image match the distributions, versions, and base hardening used in production?
Startup and provisioning time Can the target be created quickly enough for pull requests, or should slower coverage run on a scheduled pipeline?
Transport and authentication Will verification use local execution, SSH, a forwarded port, or another connection path?
CI availability Is the driver supported and permitted on every CI runner that must execute it?
Parallelism and cleanup Can multiple instances run concurrently without colliding over names, ports, networks, or credentials?
Production parity Does the test image reproduce the important kernel, init system, filesystem, and network behaviors?

Use a separate suite when the deployment contract genuinely differs, such as a database-backed installation versus a standalone node. Use multiple platforms in one suite when the same contract should hold across operating systems.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Choose where profiles live

The verifier can consume controls from several sources. A local directory is usually easiest for a role’s unit and integration tests. A Git repository is useful when several projects share a versioned security profile. A Supermarket or compliance profile can centralize controls for teams that need a common policy endpoint.

Profile source Best fit Trade-off
Local directory Controls owned and reviewed with the deployment code Reuse across repositories requires copying or packaging
Git repository Shared controls with normal code review and version tags Runs may need network access or a cached checkout
Supermarket profile Reusable community or organization profile External availability and version changes must be managed
Compliance profile Central governance and audit-oriented policy distribution Requires agreement on profile ownership and access

Pin a profile revision when reproducibility matters. A moving branch or unpinned external profile can change verification results without any change to the Ansible code.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Separate provisioning failures from verification failures

Use the first failing lifecycle phase as your initial branch.

If create fails

  • Confirm the driver plugin is installed and compatible with Test Kitchen.
  • Verify the image exists locally or is reachable from the runner.
  • Check container, hypervisor, or cloud permissions.
  • Look for host port, network, disk, and memory collisions.

If converge fails

  • Run the playbook with the same inventory and variables outside Kitchen to isolate Ansible logic.
  • Check package repositories, interpreter discovery, privilege escalation, and missing role dependencies.
  • Inspect the failed task’s module output before changing InSpec controls.

If setup or verification cannot connect

  • Confirm the verifier is configured as inspec and that the kitchen-inspec plugin is available.
  • Check the remote host, port, user, key, and sudo settings.
  • Ensure the driver exposes the address that Kitchen reports rather than an internal-only address.
  • Test the connection with the same credentials from the CI runner.

If a control fails after convergence

  • Read the actual resource value printed by InSpec.
  • Decide whether Ansible produced the wrong state or the control encoded the wrong contract.
  • Inspect the target directly before destroying it; rerun verification after a focused fix.
  • Do not weaken a security assertion merely to make the pipeline green.

Verify idempotence and re-runs

A deployment should normally converge without changing already-correct resources. Run:

  1. kitchen create INSTANCE to obtain a clean target.
  2. kitchen converge INSTANCE and save the Ansible change summary.
  3. kitchen converge INSTANCE again with identical inputs.
  4. Investigate unexpected changes in the second run, such as regenerated files, unstable ordering, timestamps, permissions, or handlers firing repeatedly.
  5. Run kitchen verify INSTANCE after the second convergence to ensure the final state still meets the contract.

Keep this check separate from the InSpec profile’s final-state controls. A role can be idempotent yet deploy the wrong port, and a role can reach the right final state while making destructive changes on every run.

Produce useful CI evidence

Run the complete Kitchen flow for pull requests when the driver is fast enough, and schedule broader platform coverage when it is slower or more expensive. Execute independent platform instances in parallel only when the driver and CI runner can isolate their networks, names, ports, and credentials.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Retain the InSpec result as a machine-readable artifact. The InSpec command set supports machine-readable formats, including JSON, which allows CI systems to archive control results, trend failures, and feed audit tooling. Also retain the Kitchen and Ansible logs for the failed lifecycle phase; a JSON verification report alone cannot explain a package repository timeout during convergence.

Destroy instances in a cleanup step that runs even when verification fails. For shared or cloud drivers, add a second cleanup safeguard so abandoned resources do not survive a cancelled CI job.

Security and reliability practices

  • Use disposable credentials with the minimum privileges needed to converge and verify.
  • Keep secrets out of kitchen.yml, control source, and CI logs.
  • Do not expose a test service to a public network unless the scenario requires it.
  • Pin driver, provisioner, verifier, platform image, and profile revisions.
  • Make timeouts explicit for package installation and endpoint checks so a network stall fails clearly.
  • Use assertions for both positive and negative requirements, such as the required port listening and an administrative port not listening.
  • Review controls when the deployment contract changes; stale controls are a maintenance failure, not a reason to ignore red results.

An end-to-end working sequence

For a new role, follow this order:

  1. Write a short contract covering packages, services, ports, files, accounts, permissions, and endpoint behavior.
  2. Create a Kitchen suite and select a driver and platform that resemble the supported deployment.
  3. Add the Ansible playbook used to converge the role, with explicit inventory and variables.
  4. Set verifier: name: inspec and point inspec_tests at the suite’s control directory.
  5. Write one focused control per contract area instead of one large control that hides the failing assertion.
  6. Run kitchen create, then kitchen converge, and fix provisioning errors.
  7. Run kitchen verify and correct either the deployment or the contract when a control fails.
  8. Converge a second time and inspect idempotence independently.
  9. Add the other supported platforms and repeat the same contract checks.
  10. Run kitchen test in CI, archive JSON results and logs, and guarantee destruction on every exit path.

Practical checklist

  • Every required outcome has an observable assertion.
  • The suite’s platform image matches a supported operating system.
  • The Ansible inventory, variables, and credentials are explicit and reproducible.
  • The kitchen-inspec verifier is configured and version-pinned.
  • Controls check package, service, port, file, user, permission, and endpoint requirements where applicable.
  • Idempotence is tested with a second converge rather than inferred from a passing verification.
  • CI preserves machine-readable InSpec output and lifecycle logs.
  • Ephemeral targets are destroyed after success, failure, and cancellation.

Using Kitchen for isolation, Ansible for convergence, and InSpec for independent assertions gives each failure a clear owner. The result is a repeatable test of what the deployment actually creates, across the platforms your role claims to support.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More from the Wire

  1. World desk4 min
    How to Spot an AI Voice Scam Before Sending MoneyDon’t rely on how a caller sounds. Pause, call back through a known number, and verify the emergency with another trusted person before sending money.
  2. Mountain View desk4 min
    Google’s SynthID Detector: How to Check AI-Generated Images, Video and AudioGoogle’s SynthID Detector looks for an embedded watermark in supported images, video and audio. Here is what its results do—and do not—show.
  3. Redmond desk20 min
    How to create a link to File or Folder in Windows 11Windows 11 gives you several ways to point to a file or folder without moving or duplicating it. You can create a desktop shortcut,…
Recommended PC Tool
Recommended PC Tool
PC Slower Than It Used to Be?Free scan - under a minute
Outdated Drivers Are Slowing You DownFree scan - exact matches

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.