Skip to content

Commit a42004d

Browse files
authored
DEVOPS-2720-added-support-for-user-key-encryption (#58)
1 parent 2d9d378 commit a42004d

File tree

6 files changed

+208
-1
lines changed

6 files changed

+208
-1
lines changed

chart/templates/backend-deployment.yaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,13 @@ spec:
6060
{{- end }}
6161
serviceAccountName: {{ template "lightrun-be.serviceAccountName" . }}
6262
volumes:
63+
- name: encryption-keys
64+
secret:
65+
secretName: {{ include "secrets.backend.name" . }}
66+
optional: false
67+
items:
68+
# Only select items that start with encryption-key-
69+
{{- include "encryption.key.items" . | nindent 18 }}
6370
{{- include "lightrun-backend.volumes.asyncProfiler" . | nindent 8 }}
6471
{{- if and .Values.general.internal_tls.enabled .Values.general.internal_tls.certificates.existing_ca_secret_name }}
6572
- name: ca-cert
@@ -123,6 +130,9 @@ spec:
123130
"/usr/src/lightrun/{{ .Values.deployments.backend.jar_name }}"
124131
]
125132
volumeMounts:
133+
- name: encryption-keys
134+
mountPath: /encryption-keys
135+
readOnly: true
126136
{{- include "lightrun-backend.volumeMounts.asyncProfiler" . | nindent 12 }}
127137
- name: jcache-config
128138
mountPath: "/jcache-config"
@@ -183,6 +193,8 @@ spec:
183193
- secretRef:
184194
name: {{ include "secrets.backend.name" . }}
185195
env:
196+
- name: SERVER_SECURITY_ENCRYPTION-KEYS-PATH
197+
value: file:/encryption-keys
186198
- name: LIGHTRUN_HOSTNAME
187199
value: {{ .Values.general.name }}
188200
- name: POD_NAME

chart/templates/helpers/_helpers.tpl

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -656,3 +656,75 @@ Returns:
656656
{{- end }}
657657
{{- $matching_queue }}
658658
{{- end }}
659+
660+
{{/*
661+
Get encryption key for Lightrun deployment. Handles existing keys, random generation, or user-provided values.
662+
*/}}
663+
{{- define "secrets.encryption-key" -}}
664+
{{- if .Values.general.deploy_secrets.enabled }}
665+
{{- if (not .Values.secrets.keysEncryption.userEncryptionKey) }}
666+
{{- $secretObj := (lookup "v1" "Secret" .Release.Namespace (include "secrets.backend.name" .)) }}
667+
{{/* Case 1: take existing generated key from secret */}}
668+
{{- if and $secretObj (hasKey $secretObj.data ( include "secrets.encryption-key-name" . ) ) }}
669+
{{- index $secretObj.data ( include "secrets.encryption-key-name" . ) | b64dec }}
670+
{{/* Case 2: generate random encryption key */}}
671+
{{- else }}
672+
{{- randBytes 32 }}
673+
{{- end }}
674+
{{/* Case 3: take user provided encryption key from values */}}
675+
{{- else }}
676+
{{- .Values.secrets.keysEncryption.userEncryptionKey }}
677+
{{- end }}
678+
{{- end }}
679+
{{- end }}
680+
681+
{{- define "secrets.encryption-key-name" -}}
682+
{{- $rotateKey := .Values.secrets.keysEncryption.rotateKey }}
683+
{{- $defaultKey := "encryption-key-0" }}
684+
{{- $keyPrefix := "encryption-key-" }}
685+
{{- $secret := (lookup "v1" "Secret" .Release.Namespace (include "secrets.backend.name" .)) }}
686+
687+
{{- $maxIndex := -1 }}
688+
{{- if $secret }}
689+
{{- range $k, $ := $secret.data }}
690+
{{- if hasPrefix $keyPrefix $k }}
691+
{{- $suffix := trimPrefix $keyPrefix $k }}
692+
{{- $num := int $suffix }}
693+
{{- if gt $num $maxIndex }}
694+
{{- $maxIndex = $num }}
695+
{{- end }}
696+
{{- end }}
697+
{{- end }}
698+
{{- end }}
699+
700+
{{- if eq $maxIndex -1 }}
701+
{{- $defaultKey }}
702+
{{- else if $rotateKey }}
703+
{{- printf "encryption-key-%d" (add1 $maxIndex) }}
704+
{{- else }}
705+
{{- printf "encryption-key-%d" $maxIndex }}
706+
{{- end }}
707+
{{- end }}
708+
709+
{{/* Helper function to render encryption key items */}}
710+
{{- define "encryption.key.items" -}}
711+
{{- $secret := (lookup "v1" "Secret" .Release.Namespace (include "secrets.backend.name" .)) -}}
712+
{{- $hasEncryptionKeys := false -}}
713+
{{- if $secret -}}
714+
{{ range $key, $value := $secret.data }}
715+
{{ if hasPrefix "encryption-key-" $key }}
716+
{{- $hasEncryptionKeys = true }}
717+
- key: {{ $key }}
718+
path: {{ $key }}
719+
{{- end }}
720+
{{- end }}
721+
{{- end }}
722+
{{ if not $hasEncryptionKeys }}
723+
- key: encryption-key-0
724+
path: encryption-key-0
725+
{{- end }}
726+
{{ if .Values.secrets.keysEncryption.rotateKey }}
727+
- key: {{ include "secrets.encryption-key-name" . }}
728+
path: {{ include "secrets.encryption-key-name" . }}
729+
{{- end }}
730+
{{- end }}

chart/templates/secrets.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ stringData:
4040
LICENSE_SIGNATURE: {{ .Values.secrets.license.signature | quote }}
4141
SPRING_RABBITMQ_USERNAME: {{ .Values.secrets.mq.user | default "" | quote }}
4242
SPRING_RABBITMQ_PASSWORD: {{ .Values.secrets.mq.password | default "" | quote }}
43+
{{ include "secrets.encryption-key-name" . }}: {{include "secrets.encryption-key" . }}
4344

4445
# Optional fields
4546
{{- if .Values.secrets.defaults.datadog_api_key }}

chart/values.yaml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -483,6 +483,25 @@ secrets:
483483
# 3. For private registry. If dockerhub_config is set to `null`, chart will not use any imagePullSecrets.
484484
existingSecret: ""
485485
configContent: ""
486+
keysEncryption:
487+
# The encryption key configuration for the backend service.
488+
# PREFERRED APPROACH: External Secret
489+
# - Create a Kubernetes secret containing the encryption key outside of this chart, see:
490+
# https://github.com/lightrun-platform/lightrun-helm-chart/blob/main/docs/installation/secrets.md
491+
# - This is the recommended approach for all environments, especially production
492+
#
493+
# ALTERNATIVE APPROACH: Chart-managed Secret
494+
# - Let the chart create and manage the secret (requires deploy_secrets.enabled=true)
495+
# - Not recommended for production environments
496+
#
497+
# IMPORTANT SECURITY NOTES:
498+
# - While you can provide an encryption key via userEncryptionKey, storing keys in values.yaml
499+
# is not secure for production environments. Use external secrets management solution
500+
# - For GitOps environments, you MUST provide a stable encryption key externally
501+
#
502+
# For more details, see: https://github.com/lightrun-platform/lightrun-helm-chart/blob/main/docs/advanced/encryption_keys.md
503+
userEncryptionKey: ""
504+
rotateKey: false
486505

487506
################
488507
## Deployments

docs/advanced/encryption_keys.md

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
# Encryption Keys
2+
3+
This document describes how to manage encryption keys for the Lightrun backend service. These keys are used to encrypt sensitive data such as:
4+
- API keys for integrations (Datadog, SIEM Integration using Splunk, etc.)
5+
- OpenAI Keys
6+
- Other sensitive configuration data
7+
8+
You can either:
9+
10+
- **Recommended**: Connect to an External Encryption Key (`general.deploy_secrets.enabled: false`)
11+
- **Not recommended for production**: Deploy a Chart-managed Encryption Key (`general.deploy_secrets.enabled: true`)
12+
13+
## Recommended Approach: External Encryption-Key (`general.deploy_secrets.enabled: false`)
14+
15+
For production environments, it's strongly recommended to manage encryption keys externally rather than letting the chart create and manage them. This approach provides better security and control over the encryption keys.
16+
17+
### Creating an External Encryption Key
18+
19+
1. Generate a secure encryption key:
20+
```bash
21+
openssl rand -base64 32
22+
```
23+
24+
> [!IMPORTANT]
25+
> The encryption key must be:
26+
> - Exactly 32 byte
27+
> - Unique for each environment
28+
> - Stored securely (e.g., in a password manager or secret management system)
29+
30+
2. Create a Kubernetes secret containing all required fields, including the encryption key. See [Secrets Documentation](../installation/secrets.md) for the complete list of required fields.
31+
32+
3. Configure the chart to use the external secret:
33+
```yaml
34+
general:
35+
deploy_secrets:
36+
enabled: false
37+
existing_secrets:
38+
backend: <secret-name>
39+
```
40+
41+
### Key Rotation with External Secrets
42+
43+
When rotating encryption keys, ensure your secret contains both the old and new encryption keys in the following format:
44+
- `encryption-key-0`: The original key
45+
- `encryption-key-1`: The new key
46+
47+
> [!IMPORTANT]
48+
> - If you have created your own encryption key, store it in a Kubernetes secret and reference it via `existing_secrets.backend`. Do not put the key directly in values.yaml
49+
> - For GitOps environments, you MUST provide stable encryption keys externally
50+
> - Keep a secure backup of your encryption keys
51+
> - Follow your organization's key rotation policies
52+
53+
## Alternative Approach: Chart-managed Encryption-Key (`general.deploy_secrets.enabled: true`)
54+
55+
For testing, POC, or development environments, you can let the chart create and manage the encryption key either by providing your own key via `keysEncryption.userEncryptionKey` or letting the chart auto-generate one if this parameter is empty. This is not recommended for production use.
56+
57+
### Steps to Use Chart-managed Secret
58+
59+
```yaml
60+
secrets:
61+
keysEncryption:
62+
userEncryptionKey: "" # Leave empty to auto-generate
63+
rotateKey: false # Set to true to enable key rotation
64+
```
65+
66+
> [!WARNING]
67+
> This approach is not recommended for production environments. Use external secrets instead.>
68+
### Key Rotation with Chart-managed secret
69+
70+
When `rotateKey` is set to `true`, the chart will:
71+
1. Generate a new key
72+
2. Store both old and new keys in the secret
73+
3. The backend will use both keys for decryption but only the new key for encryption
74+
75+
### Limitations of Chart-managed Keys
76+
77+
- For GitOps users (ArgoCD, Flux), each GitOps sync generates a new random key, making it incompatible with existing encrypted data.
78+
- While the chart provides basic key rotation, there is no backup capability and no automated rotation policies (rotation can be done proactivly in a manual way).
79+
80+
81+
> [!WARNING]
82+
> For GitOps or production environments, you MUST use external secrets management to maintain a stable encryption key.
83+

docs/installation/secrets.md

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,28 @@ general:
1717
keycloak: ""
1818
```
1919
- _(This is relevant only when `deploy_secrets: false`.)_
20+
21+
### **Mandatory Secret Fields**
22+
23+
When managing secrets externally, ensure the following fields are present in your secret (See the [secrets template](https://github.com/lightrun-platform/lightrun-helm-chart/blob/main/chart/templates/secrets.yaml#L31) for reference):
24+
25+
| Environment Variable | Description | Value Source |
26+
|---------------------|-------------|--------------|
27+
| `SPRING_SECURITY_KEYCLOAK_CLI_PASSWORD` | Keycloak admin password | `secrets.keycloak.password` |
28+
| `SPRING_MAIL_PASSWORD` | Mail server password | `secrets.defaults.mail_password` |
29+
| `SPRING_FLYWAY_PASSWORD` | DB password | `secrets.db.password` |
30+
| `SPRING_FLYWAY_USER` | DB user | `secrets.db.user` |
31+
| `SPRING_DATASOURCE_USERNAME` | DB username | `secrets.db.user` |
32+
| `SPRING_DATASOURCE_PASSWORD` | DB password | `secrets.db.password` |
33+
| `KEYSTORE_PASSWORD` | Java Keystore password | `secrets.defaults.keystore_password` |
34+
| `LICENSE_CONTENT` | Lightrun license content | `secrets.license.content` |
35+
| `LICENSE_SIGNATURE` | Lightrun license signature | `secrets.license.signature` |
36+
| `SPRING_RABBITMQ_USERNAME` | RabbitMQ username | `secrets.mq.user` |
37+
| `SPRING_RABBITMQ_PASSWORD` | RabbitMQ password | `secrets.mq.password` |
38+
| `encryption-key-0` | Backend encryption key (default) | `secrets.keysEncryption.userEncryptionKey` |
39+
2040
> [!WARNING]
21-
> If managing secrets externally, ensure all required fields are present. See the [secrets template](https://github.com/lightrun-platform/lightrun-helm-chart/blob/main/chart/templates/secrets.yaml#L31) for reference.
41+
> For encryption keys, it's strongly recommended to provide them as external secrets rather than letting the chart manage them. See [Encryption Keys Documentation](../advanced/encryption_keys.md) for details.
2242

2343
## **Secrets Configuration**
2444
### **Authentication and Access Secrets**

0 commit comments

Comments
 (0)