Skip to content

Commit 6810e77

Browse files
authored
Merge pull request #770 from jetstack/sendsecrets
Add ability to send encrypted secrets to disco backend
2 parents d6d80f4 + ec61b2a commit 6810e77

17 files changed

Lines changed: 598 additions & 49 deletions

File tree

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,5 @@ predicate.json
1515

1616
_bin
1717
.envrc
18+
19+
examples/encrypted-secrets/output.json

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ go run . agent \
3434
> - [./agent.yaml](./agent.yaml).
3535
> - [./examples/one-shot-secret.yaml](./examples/one-shot-secret.yaml).
3636
> - [./examples/cert-manager-agent.yaml](./examples/cert-manager-agent.yaml).
37+
> - [./examples/encrypted-secrets](./examples/encrypted-secrets) - Send encrypted Kubernetes secrets to CyberArk.
3738
3839
You might also want to run a local echo server to monitor requests sent by the agent:
3940

deploy/charts/disco-agent/README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,13 @@ This cluster name will be associated with the data that the agent uploads to the
295295
A short description of the cluster where the agent is deployed (optional).
296296
297297
This description will be associated with the data that the agent uploads to the Discovery and Context service. The description may include contact information such as the email address of the cluster administrator, so that any problems and risks identified by the Discovery and Context service can be communicated to the people responsible for the affected secrets.
298+
#### **config.sendSecretValues** ~ `bool`
299+
> Default value:
300+
> ```yaml
301+
> false
302+
> ```
303+
304+
Enable sending of Secret values to CyberArk in addition to metadata. Metadata is always sent, but the actual values of Secrets are not sent by default. When enabled, Secret data is encrypted using envelope encryption using a key managed by CyberArk. Default: false (but default will change to true for a future release)
298305
#### **authentication.secretName** ~ `string`
299306
> Default value:
300307
> ```yaml

deploy/charts/disco-agent/templates/deployment.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ spec:
7676
name: {{ .Values.authentication.secretName }}
7777
key: ARK_DISCOVERY_API
7878
optional: true
79+
- name: ARK_SEND_SECRET_VALUES
80+
value: {{ .Values.config.sendSecretValues | default "false" | quote }}
7981
{{- with .Values.http_proxy }}
8082
- name: HTTP_PROXY
8183
value: {{ . }}

deploy/charts/disco-agent/values.schema.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,9 @@
118118
},
119119
"period": {
120120
"$ref": "#/$defs/helm-values.config.period"
121+
},
122+
"sendSecretValues": {
123+
"$ref": "#/$defs/helm-values.config.sendSecretValues"
121124
}
122125
},
123126
"type": "object"
@@ -148,6 +151,11 @@
148151
"description": "Push data every 12 hours unless changed.",
149152
"type": "string"
150153
},
154+
"helm-values.config.sendSecretValues": {
155+
"default": false,
156+
"description": "Enable sending of Secret values to CyberArk in addition to metadata. Metadata is always sent, but the actual values of Secrets are not sent by default. When enabled, Secret data is encrypted using envelope encryption using a key managed by CyberArk. Default: false (but default will change to true for a future release)",
157+
"type": "boolean"
158+
},
151159
"helm-values.extraArgs": {
152160
"default": [],
153161
"description": "extraArgs:\n- --logging-format=json\n- --log-level=6 # To enable HTTP request logging",

deploy/charts/disco-agent/values.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,13 @@ config:
154154
# be communicated to the people responsible for the affected secrets.
155155
clusterDescription: ""
156156

157+
# Enable sending of Secret values to CyberArk in addition to metadata.
158+
# Metadata is always sent, but the actual values of Secrets are not sent by default.
159+
# When enabled, Secret data is encrypted using envelope encryption using
160+
# a key managed by CyberArk.
161+
# Default: false (but default will change to true for a future release)
162+
sendSecretValues: false
163+
157164
authentication:
158165
secretName: agent-credentials
159166

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# Encrypted Secrets Example
2+
3+
This example demonstrates how to use the disco agent to gather Kubernetes secrets and encrypt their data fields.
4+
5+
## Overview
6+
7+
When the `ARK_SEND_SECRETS` environment variable is set to `"true"`, the disco agent will:
8+
9+
0. Fetch an encryption key from the configured endpoint (if running in production) or use a local key for testing
10+
1. Discover Kubernetes secrets in your cluster (excluding common system secret types)
11+
2. Encrypt each secret's data fields using RSA envelope encryption with JWE (JSON Web Encryption) format
12+
3. If running in production, send the encrypted secrets to the configured endpoint; otherwise, write them to `output.json` for testing
13+
14+
The encryption uses:
15+
16+
- **Key Algorithm**: RSA-OAEP-256 (for encrypting the content encryption key)
17+
- **Content Encryption**: AES-256-GCM (for encrypting the actual secret data)
18+
- **Format**: JWE Compact Serialization
19+
20+
Metadata (names, namespaces, labels, annotations) remains in plaintext for discovery purposes, while the sensitive secret data is encrypted. Some keys in Secret data fields are also preserved in the `data` section, for backwards compatibility.
21+
22+
## Prerequisites
23+
24+
1. A running Kubernetes cluster with secrets to discover
25+
3. Go installed
26+
27+
## Configuration File
28+
29+
The `config.yaml` file configures:
30+
31+
- The data gatherer to collect Kubernetes secrets
32+
- Field selectors to exclude system secrets (service account tokens, docker configs, etc.)
33+
- The cluster ID and organization ID for grouping data
34+
35+
## Running the Example
36+
37+
Test the agent locally by running this script:
38+
39+
```bash
40+
./test.sh
41+
```
42+
43+
This will:
44+
45+
- Connect to your current Kubernetes context
46+
- Gather all non-system secrets
47+
- Write the raw data to `output.json`
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# encrypted-secrets config.yaml
2+
#
3+
# An example configuration file demonstrating how to use the disco agent
4+
# to send encrypted secrets to CyberArk Discovery & Context.
5+
#
6+
# The agent will:
7+
# 1. Discover Kubernetes secrets in the cluster
8+
# 2. Encrypt the secret data fields using RSA envelope encryption (JWE format)
9+
# 3. Upload the encrypted secrets to CyberArk Discovery & Context
10+
#
11+
# Example usage:
12+
#
13+
# export ARK_SUBDOMAIN="your-subdomain"
14+
# export ARK_USERNAME="your-username"
15+
# export ARK_SECRET="your-secret"
16+
# export ARK_SEND_SECRETS="true"
17+
#
18+
# go run . agent \
19+
# --agent-config-file examples/encrypted-secrets/config.yaml \
20+
# --one-shot \
21+
# --output-path output.json
22+
#
23+
organization_id: "my-organization"
24+
cluster_id: "my_cluster"
25+
period: 1m
26+
data-gatherers:
27+
- kind: "k8s-dynamic"
28+
name: "k8s/secrets"
29+
config:
30+
resource-type:
31+
version: v1
32+
resource: secrets
33+
# Filter out common system secret types to focus on application secrets
34+
field-selectors:
35+
- type!=kubernetes.io/service-account-token
36+
- type!=kubernetes.io/dockercfg
37+
- type!=kubernetes.io/dockerconfigjson
38+
- type!=kubernetes.io/basic-auth
39+
- type!=kubernetes.io/ssh-auth
40+
- type!=bootstrap.kubernetes.io/token
41+
- type!=helm.sh/release.v1

examples/encrypted-secrets/test.sh

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
#!/usr/bin/env bash
2+
# test.sh - Test script for the encrypted secrets example
3+
#
4+
# This script demonstrates running the disco agent with encrypted secrets enabled.
5+
# It will run in one-shot mode and output to a local file for inspection.
6+
7+
set -euo pipefail
8+
9+
# Colors for output
10+
RED='\033[0;31m'
11+
GREEN='\033[0;32m'
12+
YELLOW='\033[1;33m'
13+
NC='\033[0m' # No Color
14+
15+
echo -e "${GREEN}=== Encrypted Secrets Example Test ===${NC}\n"
16+
17+
echo -e "${GREEN}Testing agent with Kubernetes secrets${NC}"
18+
echo ""
19+
20+
# Enable encrypted secrets
21+
export ARK_SEND_SECRETS="true"
22+
23+
# Check Kubernetes connectivity
24+
if ! kubectl cluster-info &> /dev/null; then
25+
echo -e "${RED}Error: Unable to connect to Kubernetes cluster${NC}"
26+
echo "Please ensure your kubeconfig is configured correctly."
27+
exit 1
28+
fi
29+
30+
echo -e "${GREEN}✓ Connected to Kubernetes cluster${NC}"
31+
CONTEXT=$(kubectl config current-context)
32+
echo " Context: ${CONTEXT}"
33+
echo ""
34+
35+
# Check for secrets
36+
SECRET_COUNT=$(kubectl get secrets --all-namespaces --no-headers 2>/dev/null | wc -l | tr -d ' ')
37+
echo "Found ${SECRET_COUNT} secrets in cluster"
38+
echo ""
39+
40+
# Run the agent in one-shot mode with output to file
41+
OUTPUT_FILE="output.json"
42+
echo -e "${GREEN}Running disco agent with encrypted secrets enabled...${NC}"
43+
echo "Command: go run ../.. agent --agent-config-file config.yaml --one-shot --output-path ${OUTPUT_FILE}"
44+
echo ""
45+
46+
if go run ../.. agent \
47+
--agent-config-file config.yaml \
48+
--one-shot \
49+
--output-path "${OUTPUT_FILE}"; then
50+
51+
echo ""
52+
echo -e "${GREEN}✓ Agent completed successfully${NC}"
53+
54+
# Check if output file was created
55+
if [ -f "${OUTPUT_FILE}" ]; then
56+
echo -e "${GREEN}✓ Output file created: ${OUTPUT_FILE}${NC}"
57+
else
58+
echo -e "${RED}✗ Output file was not created${NC}"
59+
exit 1
60+
fi
61+
else
62+
echo ""
63+
echo -e "${RED}✗ Agent failed${NC}"
64+
exit 1
65+
fi

internal/cyberark/dataupload/mock.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,8 +181,8 @@ func (mds *mockDataUploadServer) handleSnapshotLinks(w http.ResponseWriter, r *h
181181
}
182182

183183
// Write response body
184-
w.WriteHeader(http.StatusOK)
185184
w.Header().Set("Content-Type", "application/json")
185+
w.WriteHeader(http.StatusOK)
186186
_ = json.NewEncoder(w).Encode(struct {
187187
URL string `json:"url"`
188188
}{presignedURL})

0 commit comments

Comments
 (0)