Secure ClickHouse Cloud with cnspec
Scan ClickHouse Cloud organizations and services against security and compliance best practices with cnspec.
Scan your ClickHouse Cloud organization to find security risks before they become incidents. cnspec evaluates which sources can reach each service, encryption at rest, private endpoint coverage, API key expiration and roles, organization membership, and other ClickHouse Cloud controls.
cnspec audits the ClickHouse Cloud control plane: services, network access, API keys, and organization members. To audit the database inside a service, its users, roles, and grants, point the clickhousedb provider at the service endpoint instead.
If you're new to cnspec, start with the Quickstart. For an overview of every database cnspec can scan, see the database scanning overview.
Prerequisites
To scan ClickHouse Cloud with cnspec, you must have:
- cnspec installed on your workstation
- A ClickHouse Cloud organization
- A ClickHouse Cloud organization API key with read access
Authenticate
cnspec connects to ClickHouse Cloud using an organization API key, which is a key ID paired with a secret. To create one:
- Log in to the ClickHouse Cloud console.
- Go to your organization's API keys page.
- Create a key, give it read access, and copy both the key ID and the secret. ClickHouse shows the secret only once.
- Copy your organization ID from the console URL or the organization's settings.
A key with read access is enough. cnspec never writes to the control plane.
Pass the organization ID, key ID, and secret on the command line. Use --ask-secret to be prompted rather than putting the secret in your shell history:
cnspec shell clickhousecloud --organization-id ORG_ID --api-key KEY_ID --ask-secretThe ClickHouse Cloud API never returns a key's secret, so cnspec can't expose one in scan results. API keys report only their ID, name, state, roles, and expiration.
Connection options
| Option | Description |
|---|---|
--organization-id | ClickHouse Cloud organization ID |
--api-key | ClickHouse Cloud API key ID |
--api-secret | ClickHouse Cloud API key secret |
--ask-secret | Prompt for the API key secret instead of passing it as a flag |
--api-url | Override the API base URL (default https://api.clickhouse.cloud/v1) |
Verify with a quick ClickHouse Cloud check
Confirm that cnspec can reach your organization by running a single query:
cnspec shell clickhousecloud --organization-id ORG_ID --api-key KEY_ID --ask-secret \
-c "clickhousecloud.organization { name }"clickhousecloud.organization: {
name: "Acme Inc"
}If clickhousecloud.organization.services comes back empty, the API key lacks read access to services. Grant it, or use a more privileged key, and try again.
Scan ClickHouse Cloud
cnspec scan clickhousecloud --organization-id ORG_ID --api-key KEY_ID --ask-secretWhen a scan completes, cnspec prints a summary of all the checks it ran, grouped by policy, along with a risk score from 0 (no risk) to 100 (highest risk). Failed checks include remediation guidance to help you fix issues. To learn more about reading scan results, read Understand cnspec Results.
Mondoo doesn't yet ship an out-of-the-box ClickHouse Cloud policy, so use the checks below as a starting point and create your own policies to meet your specific requirements.
Explore and test checks interactively
Open a cnspec shell to discover resources and try out checks:
cnspec shell clickhousecloud --organization-id ORG_ID --api-key KEY_ID --ask-secretList all services
cnspec> clickhousecloud.organization.services { name region cloudProvider state tier }
clickhousecloud.organization.services: [
0: {
name: "analytics-prod"
region: "eu-central-1"
cloudProvider: "aws"
state: "running"
tier: "production"
}
]Inspect a service's IP allow list
cnspec> clickhousecloud.organization.services { name openToAllIps ipAccessList { source description } }List a service's connection endpoints
cnspec> clickhousecloud.organization.services { name endpoints { protocol host port } }List API keys
cnspec> clickhousecloud.organization.apiKeys { name state roles neverExpires expiresAt usedAt }
clickhousecloud.organization.apiKeys: [
0: {
name: "cnspec"
state: "enabled"
roles: ["Admin"]
neverExpires: false
}
]List organization members
cnspec> clickhousecloud.organization.members { email name role }Example security checks
Ensure no service is reachable from any IP address
cnspec> clickhousecloud.organization.services.none(openToAllIps == true)
[ok] value: trueEnsure no allow-list entry opens a service to the whole internet
openToAllIps covers the common case. Testing the entries themselves also catches the IPv6 wildcard:
cnspec> clickhousecloud.organization.services.all(ipAccessList.none(source == "0.0.0.0/0" || source == "::/0"))
[ok] value: trueEnsure services encrypt data at rest with a customer-managed key
cnspec> clickhousecloud.organization.services.all(hasTransparentDataEncryption == true)
[ok] value: trueScoping this to production with .where(tier == "production") looks tempting, but tier is empty on scale-tier organizations. On one of those the filter matches nothing and the check passes without evaluating a single service. Test every service, or filter on something the organization actually populates.
Ensure services are reachable over a private endpoint
A service with private endpoints attached doesn't have to accept connections across the public internet:
cnspec> clickhousecloud.organization.services.all(hasPrivateEndpoints == true)
[ok] value: trueEnsure no API key lives forever
cnspec> clickhousecloud.organization.apiKeys.none(neverExpires == true)
[ok] value: trueEnsure no API key has gone unused
A key with a null usedAt was never used and keeps working until someone revokes it:
cnspec> clickhousecloud.organization.apiKeys.where(state == "enabled").all(usedAt != null)
[ok] value: trueEnsure an expired key is also disabled
A key that never expires has a null expiresAt, so exclude those before comparing:
cnspec> clickhousecloud.organization.apiKeys.where(state == "enabled" && neverExpires == false).none(expiresAt < time.now)
[ok] value: trueReview which API keys hold the Admin role
An Admin key can change the organization, not just read it:
cnspec> clickhousecloud.organization.apiKeys.where(roles.contains("Admin")) { name state usedAt }Review who administers the organization
cnspec> clickhousecloud.organization.members.where(role == "admin") { email name }Review the protocols each service accepts
Every endpoint is a way in. A service that publishes a MySQL-protocol endpoint alongside its native one has a second surface to account for:
cnspec> clickhousecloud.organization.services { name endpoints { protocol host port } }Learn more
- ClickHouse Cloud Resource Pack Reference: every ClickHouse Cloud resource and field cnspec can query
- Secure ClickHouse with cnspec: auditing users, roles, and grants inside a service
- Write Effective MQL: guide to authoring checks and queries