Remote Scanning with Inventory Files

Scan remote systems, network devices, and cloud accounts by defining targets and credentials in a single inventory file.

Running queries and query packs against one asset at a time works well while you explore, but most fleets have many assets. cnspec can scan the machine it's installed on, but many targets such as network devices, cloud accounts, SaaS tenants, and servers where you can't install cnspec require remote access. An inventory file lets you list those remote targets in one place, along with the credentials cnspec needs to reach them, so you can scan your entire fleet with a single command.

This page covers the cnspec inventory file, a YAML file you author to tell cnspec what to scan. Looking for the assets Mondoo has already discovered and cataloged in your space instead? See Inventory Your Assets.

An inventory file is a YAML document that defines:

  • What to scan: hosts, cloud accounts, Kubernetes clusters, SaaS tenants, and more
  • How to connect: SSH, WinRM, cloud APIs, container runtimes, and other connection types
  • How to authenticate: passwords, SSH keys, API tokens, or references to an external vault such as HashiCorp Vault or AWS Secrets Manager

Pass the file to cnspec with --inventory-file:

cnspec scan --inventory-file inventory.yml

You can also pipe an inventory from stdin instead of a file, which is useful when a previous step in a pipeline generates it:

cat inventory.yml | cnspec scan --inventory-file -

Structure

Every inventory file follows this structure:

inventory.yml
apiVersion: v1
kind: Inventory
metadata:
  name: my-inventory
  labels:
    environment: production
spec:
  assets:
    - name: display-name
      connections:
        - type: ssh
          host: 10.0.0.1
          port: 22
          credentials:
            - user: ubuntu
              private_key_path: ./id_rsa
  credentials:
    # Optional: central credential store (referenced by secret_id)
  vault:
    # Optional: external vault configuration

Top-level fields

FieldDescription
apiVersionAlways v1.
kindAlways Inventory.
metadata.nameA human-readable name for the inventory.
metadata.labelsKey-value pairs for organizing the inventory itself.
spec.assetsList of assets to scan.
spec.credentialsOptional map of named credentials (see Reference credentials with secret_id).
spec.vaultOptional external vault configuration (see Vault integration).
spec.credential_queryOptional MQL query for dynamic credential resolution.

Asset fields

Each entry in spec.assets supports:

FieldDescription
nameDisplay name for the asset.
idOptional unique identifier.
connectionsList of connection configurations.
annotationsKey-value metadata that displays in Mondoo App.
labelsKey-value pairs for filtering and grouping.

Connection fields

FieldDescription
typeConnection type, such as ssh, winrm, aws, azure, gcp, k8s, docker, vsphere, ms365, google-workspace, or local. cnspec also supports many other providers; see Supported Targets.
hostHostname or IP address.
portPort number (defaults depend on connection type).
credentialsList of credentials for this connection.
discoverOptional discovery configuration (see Discovery).
sudoOptional sudo configuration for privilege escalation (see Sudo).
insecureSet to true to skip TLS verification.
optionsProvider-specific key-value options.

Credentials

The simplest approach is to specify credentials directly on each connection. For larger inventories, you can define credentials once and reference them across assets, or pull them from an external vault.

Inline credentials

Specify credentials directly on a connection:

SSH with password
spec:
  assets:
    - name: web-server
      connections:
        - type: ssh
          host: 192.168.1.10
          credentials:
            - type: password
              user: admin
              password: s3cret
SSH with private key file
spec:
  assets:
    - name: web-server
      connections:
        - type: ssh
          host: 192.168.1.10
          credentials:
            - user: ubuntu
              private_key_path: ~/.ssh/id_rsa
SSH with inline private key (base64-encoded)
spec:
  assets:
    - name: web-server
      connections:
        - type: ssh
          host: 192.168.1.10
          credentials:
            - user: ubuntu
              private_key: <base64-encoded private key>

To encode your key, run:

base64 -i ~/.ssh/id_rsa

The credential type is inferred automatically when you use password, private_key, or private_key_path. You don't need to set type explicitly in most cases.

SSH agent

Use the system SSH agent instead of storing keys:

credentials:
  - type: ssh_agent
    user: ubuntu

Reference credentials with secret_id

When multiple assets share the same credentials, define them once in spec.credentials and reference them by secret_id:

inventory.yml
spec:
  assets:
    - name: web-01
      connections:
        - type: ssh
          host: 10.0.0.1
          credentials:
            - secret_id: my-ssh-key
    - name: web-02
      connections:
        - type: ssh
          host: 10.0.0.2
          credentials:
            - secret_id: my-ssh-key
  credentials:
    my-ssh-key:
      user: ubuntu
      private_key_path: ~/.ssh/id_rsa

Environment variables

Load a credential value from an environment variable:

spec:
  credentials:
    my-env-secret:
      type: env
      env: MY_SECRET_VAR

Dynamic credentials with credential_query

For large or heterogeneous inventories, you can resolve credentials dynamically instead of listing a secret_id on every connection. Set spec.credential_query to an MQL expression. cnspec evaluates it once per asset, with mrn, name, labels, and platform available as query properties, and expects it to return an object such as { user, type, secret_id }:

spec:
  credential_query: "return { user: 'auditor', type: 'ssh_agent' }"

cnspec only falls back to credential_query for a connection that doesn't already specify its own credentials. To learn how to write the expression itself, read Write Effective MQL.

Credential types

TypeDescription
passwordUsername and password.
private_keySSH private key (PEM-encoded, inline or loaded from a file).
ssh_agentSystem SSH agent forwarding.
bearerBearer token for API authentication.
jsonJSON-encoded secret (for example, a cloud service account key file).
pkcs12Certificate-based authentication (.p12, .pfx, or PEM combo file).
envLoad the secret from an environment variable.
aws_ec2_instance_connectAWS EC2 Instance Connect.
aws_ec2_ssm_sessionAWS Systems Manager Session Manager.

When you use private_key_path with a relative path, it resolves relative to the inventory file location, not your current working directory. For example, if your inventory is at /etc/mondoo/inventory.yml and contains private_key_path: ./keys/id_rsa, cnspec looks for /etc/mondoo/keys/id_rsa. Paths starting with ~/ expand to the current user's home directory. Absolute paths are used as-is.

Vault integration

Instead of storing secrets in the inventory file, you can use an external vault. Define the vault in spec.vault and reference secrets by their vault key:

inventory.yml
spec:
  assets:
    - name: vsphere-env
      connections:
        - type: vsphere
          host: 192.168.5.24
          insecure: true
          credentials:
            - secret_id: vcenter/mondoo-read
          discover:
            targets:
              - auto
  vault:
    name: my-vault
    type: hashicorp-vault
    options:
      url: http://127.0.0.1:8200
      token: XXXXXXXX

Supported vault types

TypeDescription
keyringSystem keyring (macOS Keychain, GNOME Keyring, Windows Credential Manager).
linux-kernel-keyringLinux kernel keyring (persistent).
encrypted-fileLocal encrypted file. Options: path, password.
hashicorp-vaultHashiCorp Vault server. Options: url, token.
aws-secrets-managerAWS Secrets Manager. Uses AWS environment credentials.
aws-parameter-storeAWS Systems Manager Parameter Store. Uses AWS environment credentials.
gcp-secret-managerGoogle Cloud Secret Manager. Options: project-id.
gcp-berglasGCP Berglas. Options: project-id, kms-key-id, bucket-name.

Configure a vault from the CLI

You can add vault configuration directly to an existing inventory file:

cnspec vault configure my-vault \
  --type hashicorp-vault \
  --option url=http://127.0.0.1:8200 \
  --option token=XXXXXXXX \
  --inventory-file inventory.yml

To store a secret in the configured vault:

cnspec vault add-secret my-secret-id "secret-value" \
  --inventory-file inventory.yml

Discovery

Some connection types can automatically find and scan related assets, such as every EC2 instance in an AWS account or every container running on a host. Use the discover block to enable this:

AWS with discovery
spec:
  assets:
    - name: aws-account
      connections:
        - type: aws
          discover:
            targets:
              - auto
          options:
            profile: production
Local machine with containers
spec:
  assets:
    - connections:
        - type: local
          discover:
            targets:
              - container

Discovery targets are defined per provider; there's no universal list. auto (discover what the provider recommends by default) and all (discover everything the provider supports) are common conventions, but not every provider implements both, and many define additional targets specific to what they connect to, such as databases for postgresdb or host-machines for vsphere. Check the connection type's page under Supported Targets for the exact targets it accepts before relying on a target name.

Annotations

Add metadata to assets that appears in Mondoo App:

spec:
  assets:
    - name: prod-web
      connections:
        - type: ssh
          host: 10.0.0.1
          credentials:
            - type: ssh_agent
              user: ubuntu
      annotations:
        Owner: ops-team
        Environment: production

You can also pass annotations from the CLI. They apply to all assets in the inventory and are merged with any annotations defined in the file:

cnspec scan --inventory-file inventory.yml --annotation Environment=staging

Pass --annotation multiple times to set more than one key:

cnspec scan --inventory-file inventory.yml \
  --annotation Environment=staging \
  --annotation Owner=ops-team

Sudo

To run scans with elevated privileges over SSH, enable sudo on the connection:

connections:
  - type: ssh
    host: 10.0.0.1
    credentials:
      - type: ssh_agent
        user: deploy
    sudo:
      active: true
      user: root

Inventory templates

Instead of hardcoding connection details, you can use templates to substitute environment variables at scan time. Use the getenv function to reference them:

template.yml
spec:
  assets:
    - name: { { getenv "ASSET_NAME" } }
      connections:
        - type: ssh
          host: { { getenv "TARGET_HOST" } }
          credentials:
            - user: { { getenv "SSH_USER" } }
              private_key_path: { { getenv "SSH_KEY_PATH" } }

Run the template with --inventory-template:

ASSET_NAME="web-01" TARGET_HOST="10.0.0.1" SSH_USER="ubuntu" SSH_KEY_PATH="~/.ssh/id_rsa" \
  cnspec scan --inventory-template template.yml

Templates are useful in CI/CD pipelines where connection details vary between environments.

Alternative inventory formats

Ansible inventory

cnspec can read Ansible inventory files in JSON format. Generate one with:

ansible-inventory --list > ansible-inventory.json

Then scan using:

cnspec scan --inventory-file ansible-inventory.json --inventory-format-ansible

Domain list

A plain text file with one hostname per line:

hosts.txt
# Production web servers
web-01.example.com
web-02.example.com
192.168.1.50:2222

Scan with:

cnspec scan --inventory-file hosts.txt --inventory-format-domainlist

Examples

Multi-cloud inventory

inventory.yml
apiVersion: v1
kind: Inventory
metadata:
  name: multi-cloud
spec:
  assets:
    - name: aws-production
      connections:
        - type: aws
          options:
            profile: prod-account
          discover:
            targets:
              - auto
    - name: gcp-project
      connections:
        - type: gcp
          options:
            project: my-gcp-project
          discover:
            targets:
              - auto
    - name: azure-tenant
      connections:
        - type: azure
          credentials:
            - type: pkcs12
              private_key_path: ./azure-cert.pem
          options:
            client-id: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
            tenant-id: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
          discover:
            targets:
              - auto

SSH fleet with shared credentials

inventory.yml
apiVersion: v1
kind: Inventory
metadata:
  name: ssh-fleet
spec:
  assets:
    - name: web-01
      connections:
        - type: ssh
          host: 10.0.0.1
          credentials:
            - secret_id: fleet-key
    - name: web-02
      connections:
        - type: ssh
          host: 10.0.0.2
          credentials:
            - secret_id: fleet-key
    - name: db-01
      connections:
        - type: ssh
          host: 10.0.1.1
          credentials:
            - secret_id: fleet-key
  credentials:
    fleet-key:
      user: ubuntu
      private_key_path: ~/.ssh/fleet_id_rsa

Microsoft 365

inventory.yml
apiVersion: v1
kind: Inventory
metadata:
  name: m365-inventory
spec:
  assets:
    - connections:
        - type: ms365
          credentials:
            - type: pkcs12
              private_key_path: ./certificate.pem
          options:
            client-id: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
            tenant-id: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
          discover:
            targets:
              - auto

Kubernetes

inventory.yml
apiVersion: v1
kind: Inventory
metadata:
  name: k8s-inventory
spec:
  assets:
    - name: production-cluster
      connections:
        - type: k8s
          options:
            kubeconfig: ~/.kube/config
            context: production
          discover:
            targets:
              - auto

vSphere with HashiCorp Vault

inventory.yml
apiVersion: v1
kind: Inventory
metadata:
  name: vsphere-inventory
spec:
  assets:
    - name: vsphere
      connections:
        - type: vsphere
          host: vcenter.example.com
          insecure: true
          credentials:
            - secret_id: vcenter/admin
          discover:
            targets:
              - host-machines
      annotations:
        Owner: infra-team
  vault:
    name: hcv
    type: hashicorp-vault
    options:
      url: http://vault.internal:8200
      token: s.xxxxxxxxxxxxxxxxxxxxxxxx

Network device fleet

Network devices often need connector-specific values, such as a privileged exec (enable) password, that aren't credentials cnspec resolves through the credential store. Set those under the connection's options instead:

inventory.yml
apiVersion: v1
kind: Inventory
metadata:
  name: network-fleet
spec:
  assets:
    - name: core-switch-01
      connections:
        - type: nd-ssh
          host: 10.10.0.1
          credentials:
            - user: admin
              password: s3cret
          options:
            enable-password: en4blepw
    - name: edge-router-01
      connections:
        - type: junos
          host: 10.10.0.2
          port: 830
          credentials:
            - secret_id: network-fleet-key
  credentials:
    network-fleet-key:
      user: admin
      private_key_path: ~/.ssh/network_id_rsa

Some connectors accept authentication-related values, such as the network device connector's enable-password for privileged exec mode, as provider options rather than credentials. Options aren't resolved through secret_id or vault references, so treat any sensitive option value with the same care you'd give a plaintext secret. Check each device page under network device scanning for which fields are options versus credentials.

Combine a host scan with its local database

A self-managed database usually runs on a host cnspec already scans at the OS level, often as a registered service with its own mondoo.yml. You don't need to re-register the host or touch mondoo.yml to add the database. Drop an inventory file beside it that lists both the host and the database, and restart cnspec so it picks up the change.

1. Find the configuration file

A host running cnspec as a service almost always uses the system-wide mondoo.yml path:

OSPath
Linux/etc/opt/mondoo/mondoo.yml
WindowsC:\ProgramData\Mondoo\mondoo.yml

For the full list, including per-user paths, read Where cnspec looks for the file. If you're not sure which one a given host actually loaded, run cnspec status; it names the file.

2. Create inventory.yml beside it

Name the file inventory.yml and place it in the same directory as mondoo.yml:

/etc/opt/mondoo/
├── mondoo.yml
└── inventory.yml

List two assets: a local connection for the host cnspec is already scanning, and a database connection pointed at localhost for the service running on it.

List both assets. If the file defines only the database, cnspec drops the existing host scan entirely rather than adding to it, because an inventory file with any assets in it replaces the default local target instead of extending it.

inventory.yml
apiVersion: v1
kind: Inventory
metadata:
  name: host-with-local-database
spec:
  assets:
    - name: db-host-os
      connections:
        - type: local
    - name: db-host-postgres
      connections:
        - type: postgresdb
          host: localhost
          credentials:
            - user: auditor
              password: s3cret

The same pattern works for any self-managed database type. For a Windows host running SQL Server, swap the second asset's connection type and credentials:

inventory.yml
apiVersion: v1
kind: Inventory
metadata:
  name: host-with-local-database
spec:
  assets:
    - name: db-host-os
      connections:
        - type: local
    - name: db-host-sqlserver
      connections:
        - type: mssql
          host: localhost
          credentials:
            - user: auditor
              password: s3cret

3. Restart cnspec

cnspec reads mondoo.yml and the inventory file once, when the service starts, and keeps that in memory for as long as it runs. It does not watch the file for changes, so a service that's already running won't notice a new or edited inventory.yml on its own. Restart it to pick up the change:

Linux (systemd)
sudo systemctl restart cnspec
Windows (PowerShell, as administrator)
Restart-Service -Name mondoo

The next scan cycle reports on both assets: the host, as it already did, and the database.

To check the file before restarting the service, test it directly. This scans exactly what the file defines without touching the running service, so you can confirm both assets connect and fix credentials before the change goes live:

cnspec scan --inventory-file /etc/opt/mondoo/inventory.yml

cnspec also auto-discovers this file when you run cnspec scan ad hoc, but only to enrich the target you give it, for example by copying id_detector settings, not to add its other assets. If you run cnspec scan local (with no --inventory-file flag) on a host that has this inventory.yml on disk, cnspec scans only local and drops the database asset. Pass --inventory-file explicitly, as in the test above, to scan everything the file defines outside of the service.

Database fleet

Beyond a single host, an inventory file also lets you list many separate database servers. Set discover.targets to have cnspec find every database on an instance, and share one credential across a fleet with secret_id:

inventory.yml
apiVersion: v1
kind: Inventory
metadata:
  name: database-fleet
spec:
  assets:
    - name: pg-primary
      connections:
        - type: postgresdb
          host: 10.20.0.1
          credentials:
            - secret_id: db-fleet-key
          discover:
            targets:
              - all
    - name: mysql-primary
      connections:
        - type: mysqldb
          host: 10.20.0.2
          credentials:
            - secret_id: db-fleet-key
  credentials:
    db-fleet-key:
      user: auditor
      password: s3cret

Learn more

On this page