Master Key Encryption
5 minute read
The edctl CLI tool enables secret management using coordinator-backed master key encryption. This approach supports batch operations, CI/CD integration, and offline encryption for air-gapped environments.
For GUI-based secret management, see Create Secrets in the GUI.
Prerequisites
Before using edctl for secret management, ensure you have:
- Coordinator pod deployed via the Helm chart (configured with PVC)
- kubectl access to the cluster
- edctl tool installed on your local machine
- API credentials: Organization ID and Pipeline ID (API key)
Install edctl
The install script automatically detects your platform and installs the latest version:
curl -sSfL https://release.edgedelta.com/tools/edctl/install.sh | bash
To install a specific version:
curl -sSfL https://release.edgedelta.com/tools/edctl/install.sh | EDCTL_VERSION=1.0.0 bash
The script will:
- Detect your OS and architecture (Linux/macOS, amd64/arm64)
- Download the appropriate binary
- Verify the checksum
- Install to
/usr/local/bin/edctl
Verify the installation:
edctl version
edctl --help
Connect to the Coordinator
The coordinator pod exposes a gRPC endpoint on port 5555. Port-forward this endpoint to your local machine.
Find the Coordinator Pod
kubectl get pods -n edgedelta | grep coordinator
Example output:
edgedelta-coordinator-56467c65f5-9rhz4 1/1 Running 0 5d
Port-Forward
kubectl port-forward -n edgedelta edgedelta-coordinator-56467c65f5-9rhz4 5555:5555
Keep this terminal open while using edctl.
Verify Connection
In another terminal:
edctl secrets encrypt --coordinator-addr=localhost:5555 --secret-id=test --value="hello"
If successful, you’ll see an encrypted value starting with edk1_.
Create a Single Secret
Use this workflow when creating one secret at a time.
Step 1: Encrypt the Secret Value
edctl secrets encrypt \
--coordinator-addr=localhost:5555 \
--secret-id=db-password \
--value="MyS3cureP@ssw0rd"
Output:
edk1_co6MwY568hGx9ZvKq8w3X2Lm4PfNj5tR7yU...
Copy this encrypted value for the next step.
Step 2: Create the Secret
Create a JSONL file with the encrypted value:
cat > secret.jsonl <<EOF
{"secret_id":"db-password","encrypted":"edk1_co6MwY568hGx9ZvKq8w3X2Lm4PfNj5tR7yU..."}
EOF
Then create the secret:
edctl secrets create \
--org-id=<organization-id> \
--pipeline-id=<pipeline-id> \
--file=secret.jsonl
Alternative using ED_API_KEY environment variable:
export ED_API_KEY=<pipeline-id>
edctl secrets create \
--org-id=<organization-id> \
--file=secret.jsonl
Success output:
Secrets created successfully
Step 3: Deploy Configuration
After creating the secret, deploy the pipeline configuration to activate it.
Create Multiple Secrets (Batch Mode)
Use batch mode when managing multiple secrets at once.
Step 1: Prepare Input File
Create a JSONL file (one JSON object per line) with your secrets:
secrets.jsonl:
{"secret_id":"db-password","value":"MyS3cureP@ssw0rd"}
{"secret_id":"api-key","value":"sk_live_abc123xyz"}
{"secret_id":"oauth-secret","value":"super-secret-oauth-key"}
{"secret_id":"jwt-signing-key","value":"my-jwt-secret-2024"}
Format requirements:
- One JSON object per line
- Each object must have
secret_idandvaluefields - Secret IDs must be unique
Step 2: Batch Encrypt
edctl secrets encrypt \
--coordinator-addr=localhost:5555 \
--input=secrets.jsonl \
--output=encrypted.jsonl
Output file (encrypted.jsonl):
{"secret_id":"db-password","encrypted":"edk1_co6MwY568h..."}
{"secret_id":"api-key","encrypted":"edk1_Ab3xYz123..."}
{"secret_id":"oauth-secret","encrypted":"edk1_Qw9ert456..."}
{"secret_id":"jwt-signing-key","encrypted":"edk1_Zx7cvb890..."}
Step 3: Create Secrets in Pipeline
edctl secrets create \
--org-id=<organization-id> \
--pipeline-id=<pipeline-id> \
--file=encrypted.jsonl
Step 4: Verify in Pipeline Configuration
The secrets are now available in the pipeline YAML:
secrets:
db-password:
value: edk1_co6MwY568h...
api-key:
value: edk1_Ab3xYz123...
oauth-secret:
value: edk1_Qw9ert456...
jwt-signing-key:
value: edk1_Zx7cvb890...
Deploy the pipeline configuration to activate the secrets.
Rotate Secrets
Rotate a Single Secret
Use the same secret ID as the existing secret:
edctl secrets encrypt \
--coordinator-addr=localhost:5555 \
--secret-id=db-password \
--value="NewS3cureP@ssw0rd2024"
Create a JSONL file and update:
cat > rotation.jsonl <<EOF
{"secret_id":"db-password","encrypted":"edk1_Yx8mnb432hFd9QwEr5tY2zK4jP6vN8aL..."}
EOF
edctl secrets update \
--org-id=<organization-id> \
--pipeline-id=<pipeline-id> \
--file=rotation.jsonl
The update command fails if the secret doesn’t exist. Use create for new secrets.
Rotate Multiple Secrets (Batch)
Prepare a rotation file with the same secret IDs but new values:
secrets-rotation.jsonl:
{"secret_id":"db-password","value":"NewS3cureP@ssw0rd2024"}
{"secret_id":"api-key","value":"sk_live_xyz789new"}
{"secret_id":"oauth-secret","value":"new-oauth-secret-2024"}
Encrypt and update:
edctl secrets encrypt \
--coordinator-addr=localhost:5555 \
--input=secrets-rotation.jsonl \
--output=encrypted-rotation.jsonl
edctl secrets update \
--org-id=<organization-id> \
--pipeline-id=<pipeline-id> \
--file=encrypted-rotation.jsonl
Deploy the pipeline configuration to activate the rotated secrets.
Offline Mode
For environments where direct coordinator access is restricted (CI/CD pipelines, air-gapped environments), export the master key and work offline.
Export the Master Key
Security Warning: The master key is sensitive cryptographic material. Handle with care.
edctl secrets export-key \
--coordinator-addr=localhost:5555 \
--output=master-key.txt
Interactive prompts:
⚠️ WARNING: Exporting master key to disk. This is sensitive cryptographic material.
Continue? (yes/no): yes
✅ Master key exported to master-key.txt
⚠️ IMPORTANT: Secure this file immediately! File permissions set to 0400.
Skip prompts with --force:
edctl secrets export-key \
--coordinator-addr=localhost:5555 \
--output=master-key.txt \
--force
Encrypt with Master Key File
Use --key-file instead of --coordinator-addr:
Encrypt a single value:
edctl secrets encrypt \
--key-file=master-key.txt \
--secret-id=db-password \
--value="MyS3cureP@ssw0rd"
Batch encrypt:
edctl secrets encrypt \
--key-file=master-key.txt \
--input=secrets.jsonl \
--output=encrypted.jsonl
Decrypt (for verification):
edctl secrets decrypt \
--key-file=master-key.txt \
--encrypted="edk1_co6MwY568h..."
Output:
secret ID: db-password, value: MyS3cureP@ssw0rd
Deploying Configuration Changes
After creating or updating secrets, deploy the pipeline configuration for changes to take effect.
Until deployment:
- New secrets are saved but not active
- Updated secrets retain their old values in running agents
- Secret references continue using previous values
Quick Reference
Common Commands
# Port-forward to coordinator
kubectl port-forward -n <namespace> <coordinator-pod> 5555:5555
# Encrypt single value
edctl secrets encrypt \
--coordinator-addr=localhost:5555 \
--secret-id=<id> \
--value="<value>"
# Encrypt batch
edctl secrets encrypt \
--coordinator-addr=localhost:5555 \
--input=secrets.jsonl \
--output=encrypted.jsonl
# Create secrets
edctl secrets create \
--org-id=<org-id> \
--pipeline-id=<pipeline-id> \
--file=encrypted.jsonl
# Update secrets (rotation)
edctl secrets update \
--org-id=<org-id> \
--pipeline-id=<pipeline-id> \
--file=encrypted.jsonl
# Export master key (offline mode)
edctl secrets export-key \
--coordinator-addr=localhost:5555 \
--output=master-key.txt
# Decrypt (verification)
edctl secrets decrypt \
--key-file=master-key.txt \
--encrypted="edk1_..."
JSONL File Formats
Input for encryption (plaintext):
{"secret_id":"my-secret","value":"plain-text-value"}
Output after encryption:
{"secret_id":"my-secret","encrypted":"edk1_co6MwY568h..."}
Environment Variables
| Variable | Description |
|---|---|
ED_API_KEY | Pipeline ID (alternative to --pipeline-id flag) |
ED_API_ENDPOINT | API endpoint (defaults to production) |
See Also
- Secrets Overview - Conceptual overview of secrets management
- Create Secrets in the GUI - GUI-based secret management
- Secrets Troubleshooting - Common issues and solutions