Decryption using SOPS
This tutorial demonstrates how to work with source manifests that are encrypted using SOPS. Component-operator currently supports two encryption engines: GPG and age. In this example, we’ll use age. The component-operator implementation works analogous to how Flux handles SOPS decryption.
For more details on decryption configuration, see Sources.
Prerequisites
You need a Kubernetes cluster with Flux source-controller and component-operator installed. If you don’t have one yet, follow the Cluster Setup guide.
1. Install age
If you don’t have age installed yet, follow the installation instructions. For example, on macOS:
brew install age
2. Create a private/public keypair
Generate an age keypair:
age-keygen -o sops.agekey
The output will display your public key. Note down the public key (starting with age1...) — you’ll need it in the next steps.
Example output:
Public key: age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8p
3. Create a Kubernetes Secret
Create a secret containing the private key:
kubectl create secret generic sops --from-file=sops.agekey=sops.agekey
This secret will be used by component-operator to decrypt the manifests at runtime.
4. Prepare unencrypted manifests
Create two simple secret manifests that we’ll encrypt:
secret-1.yaml:
apiVersion: v1
kind: Secret
metadata:
name: sops-demo-1
stringData:
foo: bar-1
secret-2.yaml:
apiVersion: v1
kind: Secret
metadata:
name: sops-demo-2
stringData:
foo: bar-2
5. Encrypt the manifests with SOPS
Now encrypt both files using SOPS with your age public key.
Partial encryption (encrypt only data and stringData fields):
sops --age=<your-age-public-key> --encrypt --encrypted-regex '^(data|stringData)$' secret-1.yaml > secret-1.enc.yaml
Full encryption (encrypt the entire YAML structure):
sops --age=<your-age-public-key> --encrypt --input-type binary secret-2.yaml > secret-2.enc.yaml
Replace <your-age-public-key> with the public key from step 2 (e.g., age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8p).
The first approach uses SOPS’ ability to partially encrypt certain fields in structured data, while the second encrypts everything. Choose the approach that best fits your security requirements.
Note: It is crucial to have no more than one Kubernetes object per file, as SOPS does not handle YAML streams (multiple documents separated by
---).
6. Create a Blueprint with encrypted content
Create a Blueprint that embeds the encrypted manifests:
# sops-demo-blueprint.yaml
---
apiVersion: core.cs.sap.com/v1alpha1
kind: Blueprint
metadata:
name: sops-demo
namespace: default
spec:
files:
secret-1.yaml: |
# Paste the entire content of secret-1.enc.yaml here
secret-2.yaml: |
# Paste the entire content of secret-2.enc.yaml here
Copy the full encrypted content from secret-1.enc.yaml and secret-2.enc.yaml into the respective file entries in the Blueprint spec.
Apply the Blueprint:
kubectl apply -f sops-demo-blueprint.yaml
7. Create a Component with decryption enabled
Create a Component that references the Blueprint and enables SOPS decryption:
# sops-demo-component.yaml
---
apiVersion: core.cs.sap.com/v1alpha1
kind: Component
metadata:
name: sops-demo
namespace: default
spec:
sourceRef:
blueprint:
name: sops-demo
decryption:
provider: sops
secretRef:
name: sops
Apply the Component:
kubectl apply -f sops-demo-component.yaml
8. Verify the decrypted secrets
Check the component status:
kubectl get component sops-demo
The component should be in Ready state, confirming that the encrypted manifests were successfully decrypted and applied.
Component-operator has decrypted the manifests using the age key from the sops secret and has created the Kubernetes secrets:
kubectl get secrets sops-demo-1 sops-demo-2
You can verify that the secrets were properly decrypted:
kubectl get secret sops-demo-1 -o jsonpath='{.data.foo}' | base64 -d
# Output: bar-1
kubectl get secret sops-demo-2 -o jsonpath='{.data.foo}' | base64 -d
# Output: bar-2
9. Cleanup
Delete the component and its dependent secrets:
kubectl delete component sops-demo
The component deletion removes all dependent objects (the two secrets). The Blueprint and the SOPS key secret are not managed by the component and must be removed separately if desired:
kubectl delete blueprint sops-demo
kubectl delete secret sops