HashiCorp Vault Integration
GGScout supports integration with HashiCorp Vault to collect and monitor your secrets, including both Vault Community Edition and Vault Enterprise (self-hosted and HashiCorp Cloud Dedicated). This guide will help you set up and configure the integration.
Supported Features
Available on all editions (Community and Enterprise):
- KV1 and KV2 secret engines
- Multiple secret versions collection
- Path-based filtering
- Token-based authentication
- Optional explicit mount type (
kv-v1/kv-v2) to skipsys/*auto-detection
Available on Vault Enterprise and HashiCorp Cloud Dedicated (HCD) only:
- Namespace support
HashiCorp Cloud Dedicated Support
GGScout fully supports HashiCorp Cloud Dedicated (HCD) environments. When using HCD, namespaces are automatically included as part of the exported resource_id, following the Vault API pattern described in the HashiCorp documentation.
Namespace Filtering
Restricting Namespace Access (Enterprise and HCD only)
Namespaces are a Vault Enterprise and HCD feature. With these editions, you can limit which namespaces ggscout accesses using the namespaces configuration parameter:
[sources.vault]
type = "hashicorpvault"
vault_address = "${VAULT_ADDR}"
fetch_all_versions = true
namespaces = ["admin", "prod", "shared"] # Only fetch from these namespaces
If the namespaces parameter is not specified, ggscout will fetch secrets from all accessible namespaces. Use this parameter to limit the scope of secret collection and improve performance.
Resource-Level Filtering
You can also filter secrets by namespace directly in your include/exclude patterns. The namespace becomes part of the resource path, allowing for precise filtering:
# Include all secrets from the 'admin' namespace, 'kv' mount, under 'my_app' path
[[sources.vault.include]]
resource_ids = ["admin/kv/my_app/*"]
# Include secrets from multiple namespaces
[[sources.vault.include]]
resource_ids = ["admin/kv/*", "dev/secrets/*", "prod/database/*"]
# Exclude test secrets from all namespaces
[[sources.vault.exclude]]
resource_ids = ["*/test/*", "*/temp/*"]
The filtering works seamlessly with the namespace structure, where the resource_id format follows: namespace/mount/path
Configuration
To configure GGScout to work with HashiCorp Vault, add the following configuration to your ggscout.toml file:
Token-based Authentication
[sources.vault]
type = "hashicorpvault"
vault_address = "${VAULT_ADDR}"
fetch_all_versions = true
mode = "read"
env = "production"
owner = "devops-team@example.com"
auth.auth_mode = "token"
auth.token = "${VAULT_TOKEN}"
# Optional: Limit to specific namespaces (Vault Enterprise and HCD only)
namespaces = ["admin", "prod", "shared"]
# Standard filtering (works on all editions including Vault Community Edition)
[[sources.vault.include]]
resource_ids = ["app/*", "database/*", "api-key"]
# Namespace-aware filtering (Vault Enterprise and HCD only)
[[sources.vault.include]]
resource_ids = ["admin/kv/my_app/*", "prod/secrets/database/*"]
[[sources.vault.exclude]]
resource_ids = ["*/test/*", "*/temp/*", "dev/old-secret"]
HashiCorp Cloud Dedicated Configuration
For HashiCorp Cloud Dedicated environments, the configuration is identical, but the filtering automatically works with namespaces:
[sources.vault_hcd]
type = "hashicorpvault"
vault_address = "${HCD_VAULT_ADDR}"
fetch_all_versions = true
mode = "read"
env = "production"
owner = "devops-team@example.com"
auth.auth_mode = "token"
auth.token = "${HCD_VAULT_TOKEN}"
# Optional: Limit to specific namespaces
namespaces = ["admin", "prod", "shared"]
# Namespace-specific filtering
[[sources.vault_hcd.include]]
resource_ids = [
"admin/kv/my_app/*", # All secrets in admin namespace, kv mount, my_app path
"prod/database/credentials/*", # Database credentials in prod namespace
"shared/api-keys/*" # Shared API keys across teams
]
[[sources.vault_hcd.exclude]]
resource_ids = [
"*/test/*", # Exclude test secrets from all namespaces
"dev/temp/*", # Exclude temporary secrets in dev namespace
"*/legacy/*" # Exclude legacy secrets from all namespaces
]
Kubernetes Authentication
[sources.vault]
type = "hashicorpvault"
vault_address = "${VAULT_ADDR}"
fetch_all_versions = true
mode = "read"
env = "production"
owner = "devops-team@example.com"
auth.auth_mode = "k8s"
auth.k8s.service_account = "${KUBERNETES_SERVICE_ACCOUNT}"
auth.k8s.namespace = "${KUBERNETES_NAMESPACE}"
auth.k8s.role = "${KUBERNETES_ROLE}"
[[sources.vault.include]]
resource_ids = ["app/*", "database/*", "api-key"]
[[sources.vault.exclude]]
resource_ids = ["test/*", "temp/*", "old-secret"]
Configuration Parameters
| Parameter | Description | Required | Default Value |
|---|---|---|---|
type | Must be set to "hashicorpvault" | Yes | |
vault_address | The address of your Vault server | Yes | |
fetch_all_versions | Whether to collect all versions of secrets | Yes | |
namespaces | List of Vault namespaces to fetch from (Vault Enterprise and HCD only). If not specified, fetches from all accessible namespaces | No | All accessible namespaces |
mount_type | Secret engine type of the pinned mount(s): "kv-v1" or "kv-v2". When set, ggscout uses the declared type and skips sys/* mount-detection. Only applies when include/path pins the mount(s). | No | Auto-detected |
auth.auth_mode | Authentication mode (e.g., "token", "k8s") | Yes | |
mode | Integration mode (one of: "read", "write", "read/write") | No | "read" |
env | Environment label for categorizing secrets (e.g., "production", "staging", "development") | No | |
owner | Owner of this source (an email, usually of an employee or a team) | No | |
[[sources.<name>.include]] | Table of resource_id patterns to include (see below) | No | |
[[sources.<name>.exclude]] | Table of resource_id patterns to exclude (see below) | No |
With additional parameters depending on the chosen authentication mode:
For Token-based Authentication:
| Parameter | Description | Required | Default Value |
|---|---|---|---|
auth.token | The Vault authentication token | Yes |
For Kubernetes Authentication:
| Parameter | Description | Required | Default Value |
|---|---|---|---|
auth.k8s.service_account | The Kubernetes service account | Yes | |
auth.k8s.namespace | The Kubernetes namespace | Yes | |
auth.k8s.role | The Kubernetes role | Yes |
Environment Variables
VAULT_ADDR: The address of your Vault server (e.g.,http://localhost:8200)
For Token-based Authentication:
VAULT_TOKEN: Your Vault authentication token
For Kubernetes Authentication:
KUBERNETES_SERVICE_ACCOUNT: The Kubernetes service accountKUBERNETES_NAMESPACE: The Kubernetes namespaceKUBERNETES_ROLE: The Kubernetes role
Skipping mount detection with mount_type
ggscout auto-detects each mount's KV engine version, so this is optional — see Required Vault Policies below for why no sys/* access is needed. Declaring the type with mount_type skips detection entirely, which helps when your token is denied sys/* or when you want to avoid extra calls on every scheduled run:
[sources.vault]
type = "hashicorpvault"
vault_address = "${VAULT_ADDR}"
mount_type = "kv-v1" # or "kv-v2"
auth.auth_mode = "token"
auth.token = "${VAULT_TOKEN}"
# mount_type only applies when an include pattern (or the deprecated `path`) pins the mount:
[[sources.vault.include]]
resource_ids = ["secret/app/*"]
mount_type only takes effect when a mount is pinned by an include pattern (or the deprecated path). If no mount is pinned, ggscout falls back to auto-detection. The value applies to every mount the filters pin, so use it when those mounts share the same engine version.
Required Vault Policies
GGScout needs permission to read the secrets you want to inventory. It detects the KV engine type and version automatically (using the same per-path lookup as the vault kv CLI), so granting sys/mounts is not required.
How broad the policy needs to be depends on whether you collect a whole mount or scope to a specific path. For write modes (mode = "write" or "read/write"), also grant create and update on the data paths.
Collect a whole mount
The simplest option — grant access across the mount:
# KV2
path "secret/metadata/*" { capabilities = ["read", "list"] }
path "secret/data/*" { capabilities = ["read"] }
# KV1
path "secret/*" { capabilities = ["read", "list"] }
Scope to a specific path (least privilege)
When you set a path (or an include filter), grant access only to that path. GGScout collects it whether the path is a folder of secrets or a single secret — no access to the rest of the mount (or to sys/mounts) is needed.
A folder — every secret under a path, e.g. path = "secret/app/team":
# KV2
path "secret/metadata/app/team" { capabilities = ["list"] }
path "secret/metadata/app/team/*" { capabilities = ["read", "list"] }
path "secret/data/app/team/*" { capabilities = ["read"] }
A single secret, e.g. path = "secret/app/db-creds":
# KV2
path "secret/metadata/app/db-creds" { capabilities = ["read"] }
path "secret/data/app/db-creds" { capabilities = ["read"] }
For KV1, drop the data/ and metadata/ segments (e.g. path "secret/app/team/*").
For HashiCorp Cloud Dedicated & Enterprise (with Namespaces)
When using HCD or Vault Enterprise with namespaces, policies are scoped to the namespace where they are created. Each namespace has its own policy space, and you create policies within specific namespaces rather than using wildcards to match across namespaces.
For namespace-specific policies, you would create policies within each namespace:
# Policy created within the 'admin' namespace for KV2 secrets
path "kv/data/*" {
capabilities = ["read", "list"]
}
path "kv/metadata/*" {
capabilities = ["read", "list"]
}
# Policy for specific paths within a namespace using the + wildcard
path "kv/data/my_app/+/config" {
capabilities = ["read", "list"]
}
path "kv/metadata/my_app/+/config" {
capabilities = ["read", "list"]
}
When working with namespaces, policies are created and managed within each namespace's scope. The + wildcard character can be used within path segments as documented in the HashiCorp Vault Policies documentation, but cross-namespace policy wildcards are not supported. For more information about namespaces, see the HashiCorp Vault Namespace documentation.
Best Practices
- Use environment variables for sensitive values like
auth.token - Leverage namespace filtering in Vault Enterprise and HCD environments to precisely control which secrets are collected
- Consider using path restrictions to limit the scope of secret collection
- Enable
fetch_all_versionsto track changes in your secrets over time - Use a dedicated service account with minimal required permissions
- For HCD environments, take advantage of the automatic namespace inclusion in resource_ids for fine-grained filtering
- Use wildcard patterns like
*/test/*to exclude test secrets across all namespaces