Resource Discovery¶
Resource discovery scans Vault to find policies and roles that aren't yet managed by Kubernetes Custom Resources. This helps you migrate existing Vault configurations to declarative management.
What is Discovery?¶
When adopting Vault Access Operator in an existing environment, you likely have:
- Policies created manually via
vault policy write - Kubernetes auth roles configured directly
- Resources created by other tools or scripts
Discovery finds these unmanaged resources so you can:
- Audit what exists in Vault
- Adopt resources into Kubernetes management
- Detect configuration drift
How It Works¶
flowchart LR
A["VaultConnection<br/>(discovery.enabled=true)"] --> B["List Vault Resources<br/>(policies, roles)"]
B --> C["Filter by Pattern<br/>& Exclude System Policies"]
C --> D["Unmanaged Resources<br/>(no matching CR)"]
D --> E["Compare with<br/>K8s Resources"]
E --> F["Auto-Create CRs<br/>(if enabled)"]
F --> G["Update Status<br/>(discovered resources)"]
Enabling Discovery¶
Enable discovery on your VaultConnection:
apiVersion: vault.platform.io/v1alpha1
kind: VaultConnection
metadata:
name: vault-primary
spec:
address: https://vault.example.com:8200
auth:
kubernetes:
role: vault-access-operator
discovery:
enabled: true
interval: 1h # How often to scan
policyPatterns: # Only discover matching policies
- "app-*"
- "team-*"
rolePatterns: # Only discover matching roles
- "*-service"
excludeSystemPolicies: true # Skip root, default, etc.
Configuration Reference¶
Discovery Fields¶
| Field | Default | Description |
|---|---|---|
enabled |
false |
Enable resource discovery |
interval |
1h |
How often to scan Vault |
policyPatterns |
[] (all) |
Glob patterns for policy names |
rolePatterns |
[] (all) |
Glob patterns for role names |
excludeSystemPolicies |
true |
Skip built-in Vault policies |
customSystemPolicies |
[] |
Additional policy names to treat as system policies (excluded when excludeSystemPolicies is true) |
autoCreateCRs |
false |
Automatically create K8s CRs for discovered resources (requires targetNamespace) |
targetNamespace |
"" |
Namespace where auto-created CRs will be placed |
Auto-Create CRs¶
When autoCreateCRs is enabled, the operator automatically creates VaultPolicy and VaultRole custom resources for each discovered unmanaged Vault resource. Created resources include the vault.platform.io/adopt annotation set to "true" and the vault.platform.io/discovered-at annotation with the discovery timestamp.
discovery:
enabled: true
autoCreateCRs: true
targetNamespace: vault-managed
policyPatterns:
- "app-*"
System Policies¶
By default, these built-in policies are excluded:
root- Superuser policydefault- Default policy for all tokensresponse-wrapping- Used for wrapped responses
Viewing Discovered Resources¶
Via kubectl¶
status:
phase: Active
discoveryStatus:
lastScanAt: "2026-01-15T10:00:00Z"
unmanagedPolicies: 3
unmanagedRoles: 2
discoveredResources:
- type: policy
name: app-database-read
discoveredAt: "2026-01-15T10:00:00Z"
suggestedCRName: app-database-read
adoptionStatus: discovered
- type: policy
name: team-platform-admin
discoveredAt: "2026-01-15T10:00:00Z"
suggestedCRName: team-platform-admin
adoptionStatus: discovered
- type: role
name: api-service
discoveredAt: "2026-01-15T10:00:00Z"
suggestedCRName: api-service
adoptionStatus: discovered
Via Prometheus Metrics¶
vault_access_operator_discovery_unmanaged_resources{connection="vault-primary", type="policy"} 3
vault_access_operator_discovery_unmanaged_resources{connection="vault-primary", type="role"} 2
vault_access_operator_discovery_scans_total{connection="vault-primary", result="success"} 10
Adopting Discovered Resources¶
Once you've identified unmanaged resources, you can adopt them into Kubernetes management.
Step 1: Review the Resource¶
# Check what the policy contains
vault policy read app-database-read
# Check what the role contains
vault read auth/kubernetes/role/api-service
Step 2: Create a Kubernetes CR¶
apiVersion: vault.platform.io/v1alpha1
kind: VaultPolicy
metadata:
name: app-database-read
namespace: production
annotations:
vault.platform.io/adopt: "true" # Adopt existing resource
spec:
vaultConnectionRef:
name: vault-primary
rules:
- path: "database/creds/readonly"
capabilities: ["read"]
Step 3: Apply and Verify¶
kubectl apply -f policy.yaml
# Check adoption status
kubectl get vaultpolicy app-database-read -o yaml
Adoption Modes¶
Adopt Existing (vault.platform.io/adopt: "true")¶
- Takes ownership of existing Vault resource
- Does NOT modify the resource (initially)
- Future updates to the CR will sync to Vault
Fail on Conflict (default)¶
Without the adopt annotation:
- If resource exists in Vault, CR enters Conflict phase
- Resource is NOT overwritten
- Requires explicit adoption or deletion
Pattern Matching¶
Discovery uses glob patterns (shell-style wildcards):
| Pattern | Matches | Doesn't Match |
|---|---|---|
app-* |
app-frontend, app-backend |
my-app, frontend |
*-prod |
api-prod, web-prod |
prod-api, production |
team-*-* |
team-platform-admin |
team-platform |
Multiple Patterns¶
Multiple patterns are OR'd together:
Best Practices¶
1. Start with Detection Only¶
Don't adopt everything immediately:
Review discovered resources, understand their purpose, then adopt selectively.
2. Use Specific Patterns¶
Avoid discovering resources you don't want to manage:
3. Document Before Adopting¶
Before adoption: 1. Export current Vault config 2. Document the resource's purpose 3. Identify who/what created it 4. Confirm no other automation manages it
4. Test Adoption in Non-Production¶
- Enable discovery in staging
- Adopt a resource
- Verify no disruption
- Then proceed to production
Troubleshooting¶
Discovery Not Running¶
Symptoms: lastScanAt not updating
Check:
1. discovery.enabled is true
2. VaultConnection is in Active phase
3. Operator has permission to list policies/roles
Missing Expected Resources¶
Symptoms: Known resources not appearing in discovery
Check:
1. Pattern filters aren't excluding them
2. excludeSystemPolicies isn't filtering them
3. Resources aren't already managed by a CR
"Permission Denied" on Scan¶
Symptoms: Discovery fails with permission error
Required Vault permissions:
# For policy discovery
path "sys/policies/acl" {
capabilities = ["list"]
}
# For role discovery
path "auth/kubernetes/role" {
capabilities = ["list"]
}
Use Cases¶
Migration from CLI to GitOps¶
- Enable discovery to audit existing resources
- Generate CRs for each discovered resource
- Add
adoptannotation - Apply via GitOps pipeline
- Disable direct CLI access
Multi-Cluster Vault¶
When multiple clusters share Vault:
# Cluster A
discovery:
policyPatterns:
- "cluster-a-*"
# Cluster B
discovery:
policyPatterns:
- "cluster-b-*"
Compliance Audit¶
Use discovery to regularly check for unmanaged resources:
Alert on vault_access_operator_discovered_resources > 0 to catch configuration drift.
See Also¶
- Drift Detection - Detect changes to managed resources
- Architecture - How discovery fits in the operator
- Getting Started - Initial setup guide