From d4efd4d7665d1c2840c7bb95e41da87c3e0ae0a3 Mon Sep 17 00:00:00 2001 From: Tal Yitzhak Date: Sun, 25 May 2025 15:47:50 +0300 Subject: [PATCH 1/4] DEVOPS-2694 - Update the lightrun-k8s-operator deployment to mount Secrets as files via volumes instead of exposing them as environment variables in containers. --- .../tests_data/lightrunjavaagent.yaml | 1 + api/v1beta/lightrunjavaagent_types.go | 4 + charts/lightrun-agents/Chart.yaml | 2 +- .../templates/java-agent-cr.yaml | 1 + charts/lightrun-agents/values.yaml | 4 + .../crds/lightrunjavaagent_crd.yaml | 5 + ...gents.lightrun.com_lightrunjavaagents.yaml | 5 + .../agents_v1beta_lightrunjavaagent.yaml | 1 + config/samples/operator.yaml | 5 + docs/custom_resource.md | 3 + examples/lightrunjavaagent.yaml | 4 + examples/operator.yaml | 5 + internal/controller/patch_funcs.go | 199 +++++++++++------- lightrun-init-agent/Dockerfile | 19 +- lightrun-init-agent/update_config.sh | 80 +++++-- 15 files changed, 244 insertions(+), 94 deletions(-) diff --git a/.github/workflows/tests_data/lightrunjavaagent.yaml b/.github/workflows/tests_data/lightrunjavaagent.yaml index 6131b0b..a5f68db 100644 --- a/.github/workflows/tests_data/lightrunjavaagent.yaml +++ b/.github/workflows/tests_data/lightrunjavaagent.yaml @@ -10,6 +10,7 @@ spec: deploymentName: sample-deployment secretName: lightrun-secrets serverHostname: dogfood.internal.lightrun.com + useSecretAsEnvVars: true agentEnvVarName: JAVA_TOOL_OPTIONS agentConfig: max_log_cpu_cost: "2" diff --git a/api/v1beta/lightrunjavaagent_types.go b/api/v1beta/lightrunjavaagent_types.go index bef29df..d5a5dd9 100644 --- a/api/v1beta/lightrunjavaagent_types.go +++ b/api/v1beta/lightrunjavaagent_types.go @@ -90,6 +90,10 @@ type LightrunJavaAgentSpec struct { // +optional // Agent name for registration to the server AgentName string `json:"agentName,omitempty"` + + // UseSecretAsEnvVars determines whether to use secret values as environment variables (true) or as mounted files (false) + // +kubebuilder:default=true + UseSecretAsEnvVars bool `json:"useSecretAsEnvVars,omitempty"` } // LightrunJavaAgentStatus defines the observed state of LightrunJavaAgent diff --git a/charts/lightrun-agents/Chart.yaml b/charts/lightrun-agents/Chart.yaml index 0a6261d..9b552ae 100644 --- a/charts/lightrun-agents/Chart.yaml +++ b/charts/lightrun-agents/Chart.yaml @@ -15,4 +15,4 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.0.1 +version: 0.0.2 diff --git a/charts/lightrun-agents/templates/java-agent-cr.yaml b/charts/lightrun-agents/templates/java-agent-cr.yaml index b53808e..987cc00 100644 --- a/charts/lightrun-agents/templates/java-agent-cr.yaml +++ b/charts/lightrun-agents/templates/java-agent-cr.yaml @@ -18,6 +18,7 @@ spec: secretName: {{ .name }}-secret {{- end }} serverHostname: {{ .serverHostname }} + useSecretAsEnvVars: {{ .useSecretAsEnvVars | default true }} agentEnvVarName: {{ .agentEnvVarName | default "JAVA_TOOL_OPTIONS" }} {{- if .agentConfig }} agentConfig: {{ toYaml .agentConfig | nindent 4 }} diff --git a/charts/lightrun-agents/values.yaml b/charts/lightrun-agents/values.yaml index 62386bf..337d258 100644 --- a/charts/lightrun-agents/values.yaml +++ b/charts/lightrun-agents/values.yaml @@ -15,6 +15,7 @@ javaAgents: [] # containerSelector: # - my-container-1 # serverHostname: 'lightrun.example.com' +# useSecretAsEnvVars: true # initContainer: # image: "lightruncom/k8s-operator-init-java-agent-linux:latest" # agentPoolCredentials: @@ -34,6 +35,7 @@ javaAgents: [] # containerSelector: # - my-container-2 # serverHostname: 'lightrun.example.com' +# useSecretAsEnvVars: true # agentPoolCredentials: # existingSecret: "my-existing-secret" # apiKey: "" @@ -57,6 +59,7 @@ javaAgents: [] # containerSelector: # - my-container-1 # serverHostname: 'lightrun.example.com' +# useSecretAsEnvVars: true # agentEnvVarName: '_JAVA_OPTIONS' # agentConfig: # max_log_cpu_cost: "2" @@ -84,6 +87,7 @@ javaAgents: [] # containerSelector: # - my-container-2 # serverHostname: 'lightrun.example.com' +# useSecretAsEnvVars: true # agentEnvVarName: 'JAVA_OPTS' # agentConfig: # max_log_cpu_cost: "2" diff --git a/charts/lightrun-operator/crds/lightrunjavaagent_crd.yaml b/charts/lightrun-operator/crds/lightrunjavaagent_crd.yaml index d748749..2b283c6 100644 --- a/charts/lightrun-operator/crds/lightrunjavaagent_crd.yaml +++ b/charts/lightrun-operator/crds/lightrunjavaagent_crd.yaml @@ -119,6 +119,11 @@ spec: Lightrun server hostname that will be used for downloading an agent Key and company id in the secret has to be taken from this server as well type: string + useSecretAsEnvVars: + default: true + description: UseSecretAsEnvVars determines whether to use secret values + as environment variables (true) or as mounted files (false) + type: boolean workloadName: description: Name of the Workload that will be patched. workload can be either Deployment or StatefulSet e.g. my-deployment, my-statefulset diff --git a/config/crd/bases/agents.lightrun.com_lightrunjavaagents.yaml b/config/crd/bases/agents.lightrun.com_lightrunjavaagents.yaml index 9ca3b13..a96515a 100644 --- a/config/crd/bases/agents.lightrun.com_lightrunjavaagents.yaml +++ b/config/crd/bases/agents.lightrun.com_lightrunjavaagents.yaml @@ -120,6 +120,11 @@ spec: Lightrun server hostname that will be used for downloading an agent Key and company id in the secret has to be taken from this server as well type: string + useSecretAsEnvVars: + default: true + description: UseSecretAsEnvVars determines whether to use secret values + as environment variables (true) or as mounted files (false) + type: boolean workloadName: description: Name of the Workload that will be patched. workload can be either Deployment or StatefulSet e.g. my-deployment, my-statefulset diff --git a/config/samples/agents_v1beta_lightrunjavaagent.yaml b/config/samples/agents_v1beta_lightrunjavaagent.yaml index a0e3bb4..2f91d5b 100644 --- a/config/samples/agents_v1beta_lightrunjavaagent.yaml +++ b/config/samples/agents_v1beta_lightrunjavaagent.yaml @@ -11,6 +11,7 @@ spec: workloadType: Deployment secretName: lightrun-secrets serverHostname: #for saas it will be app.lightrun.com + useSecretAsEnvVars: true agentEnvVarName: JAVA_TOOL_OPTIONS agentConfig: max_log_cpu_cost: "2" diff --git a/config/samples/operator.yaml b/config/samples/operator.yaml index b8c65a9..a36c2c9 100644 --- a/config/samples/operator.yaml +++ b/config/samples/operator.yaml @@ -131,6 +131,11 @@ spec: Lightrun server hostname that will be used for downloading an agent Key and company id in the secret has to be taken from this server as well type: string + useSecretAsEnvVars: + default: true + description: UseSecretAsEnvVars determines whether to use secret values + as environment variables (true) or as mounted files (false) + type: boolean workloadName: description: Name of the Workload that will be patched. workload can be either Deployment or StatefulSet e.g. my-deployment, my-statefulset diff --git a/docs/custom_resource.md b/docs/custom_resource.md index 872b54f..adf898b 100644 --- a/docs/custom_resource.md +++ b/docs/custom_resource.md @@ -49,6 +49,9 @@ spec: # If container not mentioned here it will be not patched containerSelector: - app + # UseSecretAsEnvVars determines whether to use secret values as environment variables (true) or as mounted files (false) + # Default is true for backward compatibility + useSecretAsEnvVars: true --- apiVersion: v1 metadata: diff --git a/examples/lightrunjavaagent.yaml b/examples/lightrunjavaagent.yaml index b1dea07..61d5cdc 100644 --- a/examples/lightrunjavaagent.yaml +++ b/examples/lightrunjavaagent.yaml @@ -59,3 +59,7 @@ spec: - latest # Agent name. If not provided, pod name will be used #agentName: "operator-test-agent" + + # UseSecretAsEnvVars determines whether to use secret values as environment variables (true) or as mounted files (false) + # Default is true for backward compatibility + useSecretAsEnvVars: true diff --git a/examples/operator.yaml b/examples/operator.yaml index 000dfc3..994174a 100644 --- a/examples/operator.yaml +++ b/examples/operator.yaml @@ -121,6 +121,11 @@ spec: Lightrun server hostname that will be used for downloading an agent Key and company id in the secret has to be taken from this server as well type: string + useSecretAsEnvVars: + default: true + description: UseSecretAsEnvVars determines whether to use secret values + as environment variables (true) or as mounted files (false) + type: boolean workloadName: description: Name of the Workload that will be patched. workload can be either Deployment or StatefulSet e.g. my-deployment, my-statefulset diff --git a/internal/controller/patch_funcs.go b/internal/controller/patch_funcs.go index 68365a7..d229ae0 100644 --- a/internal/controller/patch_funcs.go +++ b/internal/controller/patch_funcs.go @@ -52,7 +52,6 @@ func (r *LightrunJavaAgentReconciler) createAgentConfig(lightrunJavaAgent *agent } func (r *LightrunJavaAgentReconciler) patchDeployment(lightrunJavaAgent *agentv1beta.LightrunJavaAgent, secret *corev1.Secret, origDeployment *appsv1.Deployment, deploymentApplyConfig *appsv1ac.DeploymentApplyConfiguration, cmDataHash uint64) error { - // init spec.template.spec deploymentApplyConfig.WithSpec( appsv1ac.DeploymentSpec().WithTemplate( @@ -60,8 +59,7 @@ func (r *LightrunJavaAgentReconciler) patchDeployment(lightrunJavaAgent *agentv1 corev1ac.PodSpec(), ).WithAnnotations(map[string]string{ annotationConfigMapHash: fmt.Sprint(cmDataHash), - }, - ), + }), ), ).WithAnnotations(map[string]string{ annotationAgentName: lightrunJavaAgent.Name, @@ -72,19 +70,21 @@ func (r *LightrunJavaAgentReconciler) patchDeployment(lightrunJavaAgent *agentv1 if err != nil { return err } + deploymentApplyConfig.Spec.Template.Spec.WithSecurityContext( + corev1ac.PodSecurityContext(). + WithFSGroup(1000), + ) return nil } func (r *LightrunJavaAgentReconciler) addVolume(deploymentApplyConfig *appsv1ac.DeploymentApplyConfiguration, lightrunJavaAgent *agentv1beta.LightrunJavaAgent) { - - deploymentApplyConfig.Spec.Template.Spec. - WithVolumes( - corev1ac.Volume(). - WithName(lightrunJavaAgent.Spec.InitContainer.SharedVolumeName). - WithEmptyDir( - corev1ac.EmptyDirVolumeSource(), - ), - ).WithVolumes( + // Start with base volumes + volumes := []*corev1ac.VolumeApplyConfiguration{ + corev1ac.Volume(). + WithName(lightrunJavaAgent.Spec.InitContainer.SharedVolumeName). + WithEmptyDir( + corev1ac.EmptyDirVolumeSource(), + ), corev1ac.Volume(). WithName(cmVolumeName). WithConfigMap( @@ -95,19 +95,34 @@ func (r *LightrunJavaAgentReconciler) addVolume(deploymentApplyConfig *appsv1ac. corev1ac.KeyToPath().WithKey("metadata").WithPath("agent.metadata.json"), ), ), - ) + } + + // Add secret volume if UseSecretAsEnvVars is false + if !lightrunJavaAgent.Spec.UseSecretAsEnvVars { + volumes = append(volumes, + corev1ac.Volume().WithName("lightrun-secret"). + WithSecret(corev1ac.SecretVolumeSource(). + WithSecretName(secret.Name). + WithItems( + corev1ac.KeyToPath().WithKey("lightrun_key").WithPath("lightrun_key"), + corev1ac.KeyToPath().WithKey("pinned_cert_hash").WithPath("pinned_cert_hash"), + ). + WithDefaultMode(0440)), + ) + } + + deploymentApplyConfig.Spec.Template.Spec.WithVolumes(volumes...) } func (r *LightrunJavaAgentReconciler) addInitContainer(deploymentApplyConfig *appsv1ac.DeploymentApplyConfiguration, lightrunJavaAgent *agentv1beta.LightrunJavaAgent, secret *corev1.Secret) { + // Start with base environment variables + envVars := []*corev1ac.EnvVarApplyConfiguration{ + corev1ac.EnvVar().WithName("LIGHTRUN_SERVER").WithValue(lightrunJavaAgent.Spec.ServerHostname), + } - deploymentApplyConfig.Spec.Template.Spec.WithInitContainers( - corev1ac.Container(). - WithName(initContainerName). - WithImage(lightrunJavaAgent.Spec.InitContainer.Image). - WithVolumeMounts( - corev1ac.VolumeMount().WithName(lightrunJavaAgent.Spec.InitContainer.SharedVolumeName).WithMountPath("/tmp/"), - corev1ac.VolumeMount().WithName(cmVolumeName).WithMountPath("/tmp/cm/"), - ).WithEnv( + // Add secret environment variables if UseSecretAsEnvVars is true + if lightrunJavaAgent.Spec.UseSecretAsEnvVars { + envVars = append(envVars, corev1ac.EnvVar().WithName("LIGHTRUN_KEY").WithValueFrom( corev1ac.EnvVarSource().WithSecretKeyRef( corev1ac.SecretKeySelector().WithName(secret.Name).WithKey("lightrun_key"), @@ -118,8 +133,35 @@ func (r *LightrunJavaAgentReconciler) addInitContainer(deploymentApplyConfig *ap corev1ac.SecretKeySelector().WithName(secret.Name).WithKey("pinned_cert_hash"), ), ), - corev1ac.EnvVar().WithName("LIGHTRUN_SERVER").WithValue(lightrunJavaAgent.Spec.ServerHostname), - ). + ) + } + + // Start with base volume mounts + volumeMounts := []*corev1ac.VolumeMountApplyConfiguration{ + corev1ac.VolumeMount().WithName(lightrunJavaAgent.Spec.InitContainer.SharedVolumeName).WithMountPath("/tmp/"), + corev1ac.VolumeMount().WithName(cmVolumeName).WithMountPath("/tmp/cm/"), + } + + // Add secret volume mount if UseSecretAsEnvVars is false + if !lightrunJavaAgent.Spec.UseSecretAsEnvVars { + volumeMounts = append(volumeMounts, + corev1ac.VolumeMount().WithName("lightrun-secret").WithMountPath("/etc/lightrun/secret").WithReadOnly(true), + ) + } + + deploymentApplyConfig.Spec.Template.Spec.WithInitContainers( + corev1ac.Container(). + WithName(initContainerName). + WithImage(lightrunJavaAgent.Spec.InitContainer.Image). + WithVolumeMounts(volumeMounts...). + WithEnv(envVars...). + WithSecurityContext( + corev1ac.SecurityContext(). + WithReadOnlyRootFilesystem(true). + WithAllowPrivilegeEscalation(false). + WithRunAsNonRoot(true). + WithRunAsUser(1000), + ). WithResources( corev1ac.ResourceRequirements(). WithLimits( @@ -133,18 +175,6 @@ func (r *LightrunJavaAgentReconciler) addInitContainer(deploymentApplyConfig *ap corev1.ResourceMemory: *resource.NewScaledQuantity(int64(64), resource.Scale(6)), }, ), - ). - WithSecurityContext( - corev1ac.SecurityContext(). - WithCapabilities( - corev1ac.Capabilities().WithDrop(corev1.Capability("ALL")), - ). - WithAllowPrivilegeEscalation(false). - WithRunAsNonRoot(true). - WithSeccompProfile( - corev1ac.SeccompProfile(). - WithType(corev1.SeccompProfileTypeRuntimeDefault), - ), ), ) } @@ -230,8 +260,7 @@ func (r *LightrunJavaAgentReconciler) patchStatefulSet(lightrunJavaAgent *agentv corev1ac.PodSpec(), ).WithAnnotations(map[string]string{ annotationConfigMapHash: fmt.Sprint(cmDataHash), - }, - ), + }), ), ).WithAnnotations(map[string]string{ annotationAgentName: lightrunJavaAgent.Name, @@ -239,10 +268,8 @@ func (r *LightrunJavaAgentReconciler) patchStatefulSet(lightrunJavaAgent *agentv // Add volumes to the StatefulSet r.addVolumeToStatefulSet(statefulSetApplyConfig, lightrunJavaAgent) - // Add init container to the StatefulSet r.addInitContainerToStatefulSet(statefulSetApplyConfig, lightrunJavaAgent, secret) - // Patch app containers in the StatefulSet err = r.patchStatefulSetAppContainers(lightrunJavaAgent, origStatefulSet, statefulSetApplyConfig) if err != nil { @@ -253,14 +280,13 @@ func (r *LightrunJavaAgentReconciler) patchStatefulSet(lightrunJavaAgent *agentv } func (r *LightrunJavaAgentReconciler) addVolumeToStatefulSet(statefulSetApplyConfig *appsv1ac.StatefulSetApplyConfiguration, lightrunJavaAgent *agentv1beta.LightrunJavaAgent) { - statefulSetApplyConfig.Spec.Template.Spec. - WithVolumes( - corev1ac.Volume(). - WithName(lightrunJavaAgent.Spec.InitContainer.SharedVolumeName). - WithEmptyDir( - corev1ac.EmptyDirVolumeSource(), - ), - ).WithVolumes( + // Start with base volumes + volumes := []*corev1ac.VolumeApplyConfiguration{ + corev1ac.Volume(). + WithName(lightrunJavaAgent.Spec.InitContainer.SharedVolumeName). + WithEmptyDir( + corev1ac.EmptyDirVolumeSource(), + ), corev1ac.Volume(). WithName(cmVolumeName). WithConfigMap( @@ -271,18 +297,34 @@ func (r *LightrunJavaAgentReconciler) addVolumeToStatefulSet(statefulSetApplyCon corev1ac.KeyToPath().WithKey("metadata").WithPath("agent.metadata.json"), ), ), - ) + } + + // Add secret volume if UseSecretAsEnvVars is false + if !lightrunJavaAgent.Spec.UseSecretAsEnvVars { + volumes = append(volumes, + corev1ac.Volume().WithName("lightrun-secret"). + WithSecret(corev1ac.SecretVolumeSource(). + WithSecretName(secret.Name). + WithItems( + corev1ac.KeyToPath().WithKey("lightrun_key").WithPath("lightrun_key"), + corev1ac.KeyToPath().WithKey("pinned_cert_hash").WithPath("pinned_cert_hash"), + ). + WithDefaultMode(0440)), + ) + } + + statefulSetApplyConfig.Spec.Template.Spec.WithVolumes(volumes...) } func (r *LightrunJavaAgentReconciler) addInitContainerToStatefulSet(statefulSetApplyConfig *appsv1ac.StatefulSetApplyConfiguration, lightrunJavaAgent *agentv1beta.LightrunJavaAgent, secret *corev1.Secret) { - statefulSetApplyConfig.Spec.Template.Spec.WithInitContainers( - corev1ac.Container(). - WithName(initContainerName). - WithImage(lightrunJavaAgent.Spec.InitContainer.Image). - WithVolumeMounts( - corev1ac.VolumeMount().WithName(lightrunJavaAgent.Spec.InitContainer.SharedVolumeName).WithMountPath("/tmp/"), - corev1ac.VolumeMount().WithName(cmVolumeName).WithMountPath("/tmp/cm/"), - ).WithEnv( + // Start with base environment variables + envVars := []*corev1ac.EnvVarApplyConfiguration{ + corev1ac.EnvVar().WithName("LIGHTRUN_SERVER").WithValue(lightrunJavaAgent.Spec.ServerHostname), + } + + // Add secret environment variables if UseSecretAsEnvVars is true + if lightrunJavaAgent.Spec.UseSecretAsEnvVars { + envVars = append(envVars, corev1ac.EnvVar().WithName("LIGHTRUN_KEY").WithValueFrom( corev1ac.EnvVarSource().WithSecretKeyRef( corev1ac.SecretKeySelector().WithName(secret.Name).WithKey("lightrun_key"), @@ -293,8 +335,35 @@ func (r *LightrunJavaAgentReconciler) addInitContainerToStatefulSet(statefulSetA corev1ac.SecretKeySelector().WithName(secret.Name).WithKey("pinned_cert_hash"), ), ), - corev1ac.EnvVar().WithName("LIGHTRUN_SERVER").WithValue(lightrunJavaAgent.Spec.ServerHostname), - ). + ) + } + + // Start with base volume mounts + volumeMounts := []*corev1ac.VolumeMountApplyConfiguration{ + corev1ac.VolumeMount().WithName(lightrunJavaAgent.Spec.InitContainer.SharedVolumeName).WithMountPath("/tmp/"), + corev1ac.VolumeMount().WithName(cmVolumeName).WithMountPath("/tmp/cm/"), + } + + // Add secret volume mount if UseSecretAsEnvVars is false + if !lightrunJavaAgent.Spec.UseSecretAsEnvVars { + volumeMounts = append(volumeMounts, + corev1ac.VolumeMount().WithName("lightrun-secret").WithMountPath("/etc/lightrun/secret").WithReadOnly(true), + ) + } + + statefulSetApplyConfig.Spec.Template.Spec.WithInitContainers( + corev1ac.Container(). + WithName(initContainerName). + WithImage(lightrunJavaAgent.Spec.InitContainer.Image). + WithVolumeMounts(volumeMounts...). + WithEnv(envVars...). + WithSecurityContext( + corev1ac.SecurityContext(). + WithReadOnlyRootFilesystem(true). + WithAllowPrivilegeEscalation(false). + WithRunAsNonRoot(true). + WithRunAsUser(1000), + ). WithResources( corev1ac.ResourceRequirements(). WithLimits( @@ -308,18 +377,6 @@ func (r *LightrunJavaAgentReconciler) addInitContainerToStatefulSet(statefulSetA corev1.ResourceMemory: *resource.NewScaledQuantity(int64(64), resource.Scale(6)), }, ), - ). - WithSecurityContext( - corev1ac.SecurityContext(). - WithCapabilities( - corev1ac.Capabilities().WithDrop(corev1.Capability("ALL")), - ). - WithAllowPrivilegeEscalation(false). - WithRunAsNonRoot(true). - WithSeccompProfile( - corev1ac.SeccompProfile(). - WithType(corev1.SeccompProfileTypeRuntimeDefault), - ), ), ) } @@ -335,7 +392,7 @@ func (r *LightrunJavaAgentReconciler) patchStatefulSetAppContainers(lightrunJava WithName(container.Name). WithImage(container.Image). WithVolumeMounts( - corev1ac.VolumeMount().WithMountPath(lightrunJavaAgent.Spec.InitContainer.SharedVolumeMountPath).WithName(lightrunJavaAgent.Spec.InitContainer.SharedVolumeName), + corev1ac.VolumeMount().WithName(lightrunJavaAgent.Spec.InitContainer.SharedVolumeName).WithMountPath(lightrunJavaAgent.Spec.InitContainer.SharedVolumeMountPath), ), ) } diff --git a/lightrun-init-agent/Dockerfile b/lightrun-init-agent/Dockerfile index b2dc3d3..d7aecf5 100644 --- a/lightrun-init-agent/Dockerfile +++ b/lightrun-init-agent/Dockerfile @@ -1,9 +1,9 @@ ARG base_image_tag=alpine-3.20.0-r1 FROM lightruncom/prod-base:${base_image_tag} -ARG FILE +ARG FILE -COPY lightrun-init-agent/$FILE /tmp/$FILE +COPY $FILE /tmp/$FILE RUN unzip -o /tmp/$FILE -d /agent ;\ rm -rf /tmp/$FILE && \ @@ -12,9 +12,20 @@ RUN unzip -o /tmp/$FILE -d /agent ;\ sed -i.bak "s|pinned_certs=.*|pinned_certs=|" /agent/agent.config && rm /agent/agent.config.bak && \ # In openshift UID will be dynamic per project, hence procide permissions to root group (defualt in k8s) chgrp -R 0 /agent && \ - chmod -R g=u /agent + chmod -R g=u /agent && \ + # Set proper permissions for the agent directory + chown -R 1000:1000 /agent && \ + chmod -R 750 /agent && \ + # Create secret directory with proper permissions + mkdir -p /etc/lightrun/secret && \ + chown -R 1000:1000 /etc/lightrun/secret && \ + chmod -R 700 /etc/lightrun/secret + +# Copy and set permissions for update_config.sh before switching user +COPY update_config.sh /update_config.sh +RUN chmod 750 /update_config.sh && \ + chown 1000:1000 /update_config.sh USER 1000 -COPY lightrun-init-agent/update_config.sh /update_config.sh CMD [ "/bin/sh", "/update_config.sh" ] diff --git a/lightrun-init-agent/update_config.sh b/lightrun-init-agent/update_config.sh index 52419a7..a9e58b3 100755 --- a/lightrun-init-agent/update_config.sh +++ b/lightrun-init-agent/update_config.sh @@ -1,10 +1,10 @@ #!/bin/sh # Script to initialize and configure the Lightrun agent # This script: -# 1. Validates required environment variables +# 1. Validates required environment variables and files # 2. Sets up a working directory # 3. Merges configuration files -# 4. Updates configuration with environment variables +# 4. Updates configuration with values from files # 5. Copies the final configuration to destination set -e @@ -14,23 +14,58 @@ TMP_DIR="/tmp" WORK_DIR="${TMP_DIR}/agent-workdir" FINAL_DEST="${TMP_DIR}/agent" CONFIG_MAP_DIR="${TMP_DIR}/cm" +SECRET_DIR="/etc/lightrun/secret" + +# Function to get value from either environment variable or file +get_value() { + local env_var=$1 + local file_path=$2 + local value="" + + # First try environment variable + eval "value=\$${env_var}" + if [ -n "${value}" ]; then + echo "[WARNING] Using environment variable ${env_var}. Please upgrade to the latest operator version for better security and management." >&2 + echo "[INFO] Using value from environment variable ${env_var}" >&2 + echo "${value}" + return 0 + fi + + # Then try file + if [ -f "${file_path}" ]; then + value=$(cat "${file_path}") + echo "[INFO] Using value from file ${file_path}" >&2 + echo "${value}" + return 0 + fi -# Function to validate required environment variables + echo "" + return 1 +} + +# Function to validate required files and environment variables validate_env_vars() { - local missing_vars="" + local missing_requirements="" - if [ -z "${LIGHTRUN_KEY}" ]; then - missing_vars="${missing_vars} LIGHTRUN_KEY" + # Check for LIGHTRUN_SERVER (required in both old and new versions) + if [ -z "${LIGHTRUN_SERVER}" ]; then + missing_requirements="${missing_requirements} LIGHTRUN_SERVER" fi - if [ -z "${PINNED_CERT}" ]; then - missing_vars="${missing_vars} PINNED_CERT" + + # Check for lightrun_key (either env var or file) + local lightrun_key=$(get_value "LIGHTRUN_KEY" "${SECRET_DIR}/lightrun_key") + if [ -z "${lightrun_key}" ]; then + missing_requirements="${missing_requirements} LIGHTRUN_KEY" fi - if [ -z "${LIGHTRUN_SERVER}" ]; then - missing_vars="${missing_vars} LIGHTRUN_SERVER" + + # Check for pinned_cert (either env var or file) + local pinned_cert=$(get_value "PINNED_CERT" "${SECRET_DIR}/pinned_cert_hash") + if [ -z "${pinned_cert}" ]; then + missing_requirements="${missing_requirements} PINNED_CERT" fi - if [ -n "${missing_vars}" ]; then - echo "Error: Missing required environment variables:${missing_vars}" + if [ -n "${missing_requirements}" ]; then + echo "Error: Missing required environment variables or files:${missing_requirements}" exit 1 fi } @@ -64,27 +99,36 @@ merge_configs() { rm "${temp_conf}" } -# Function to update configuration with environment variables +# Function to update configuration with values from files update_config() { - echo "Updating configuration with environment variables" + echo "Updating configuration with values from files" local config_file="${WORK_DIR}/agent.config" local missing_configuration_params="" + if [ ! -f "${config_file}" ]; then + echo "[ERROR] Config file not found at ${config_file}" + exit 1 + fi + + # Get values from either environment variables or files + local lightrun_key=$(get_value "LIGHTRUN_KEY" "${SECRET_DIR}/lightrun_key") + local pinned_cert=$(get_value "PINNED_CERT" "${SECRET_DIR}/pinned_cert_hash") + if sed -n "s|com.lightrun.server=.*|com.lightrun.server=https://${LIGHTRUN_SERVER}|p" "${config_file}" | grep -q .; then # Perform actual in-place change sed -i "s|com.lightrun.server=.*|com.lightrun.server=https://${LIGHTRUN_SERVER}|" "${config_file}" else missing_configuration_params="${missing_configuration_params} com.lightrun.server" fi - if sed -n "s|com.lightrun.secret=.*|com.lightrun.secret=${LIGHTRUN_KEY}|p" "${config_file}" | grep -q .; then + if sed -n "s|com.lightrun.secret=.*|com.lightrun.secret=${lightrun_key}|p" "${config_file}" | grep -q .; then # Perform actual in-place change - sed -i "s|com.lightrun.secret=.*|com.lightrun.secret=${LIGHTRUN_KEY}|" "${config_file}" + sed -i "s|com.lightrun.secret=.*|com.lightrun.secret=${lightrun_key}|" "${config_file}" else missing_configuration_params="${missing_configuration_params} com.lightrun.secret" fi - if sed -n "s|pinned_certs=.*|pinned_certs=${PINNED_CERT}|p" "${config_file}" | grep -q .; then + if sed -n "s|pinned_certs=.*|pinned_certs=${pinned_cert}|p" "${config_file}" | grep -q .; then # Perform actual in-place change - sed -i "s|pinned_certs=.*|pinned_certs=${PINNED_CERT}|" "${config_file}" + sed -i "s|pinned_certs=.*|pinned_certs=${pinned_cert}|" "${config_file}" else missing_configuration_params="${missing_configuration_params} pinned_certs" fi From 6bfc828b8996c8e9d29201f619629d6f31dcd376 Mon Sep 17 00:00:00 2001 From: Tal Yitzhak Date: Mon, 9 Jun 2025 23:38:23 +0300 Subject: [PATCH 2/4] Resolving PR comments --- charts/lightrun-agents/Chart.yaml | 2 +- .../templates/java-agent-cr.yaml | 2 ++ internal/controller/patch_funcs.go | 32 ++++++++++++------- lightrun-init-agent/Dockerfile | 11 +++---- 4 files changed, 28 insertions(+), 19 deletions(-) diff --git a/charts/lightrun-agents/Chart.yaml b/charts/lightrun-agents/Chart.yaml index 9b552ae..0a6261d 100644 --- a/charts/lightrun-agents/Chart.yaml +++ b/charts/lightrun-agents/Chart.yaml @@ -15,4 +15,4 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.0.2 +version: 0.0.1 diff --git a/charts/lightrun-agents/templates/java-agent-cr.yaml b/charts/lightrun-agents/templates/java-agent-cr.yaml index 987cc00..2084290 100644 --- a/charts/lightrun-agents/templates/java-agent-cr.yaml +++ b/charts/lightrun-agents/templates/java-agent-cr.yaml @@ -18,7 +18,9 @@ spec: secretName: {{ .name }}-secret {{- end }} serverHostname: {{ .serverHostname }} + {{- if .useSecretAsEnvVars }} useSecretAsEnvVars: {{ .useSecretAsEnvVars | default true }} + {{- end }} agentEnvVarName: {{ .agentEnvVarName | default "JAVA_TOOL_OPTIONS" }} {{- if .agentConfig }} agentConfig: {{ toYaml .agentConfig | nindent 4 }} diff --git a/internal/controller/patch_funcs.go b/internal/controller/patch_funcs.go index d229ae0..b8da13d 100644 --- a/internal/controller/patch_funcs.go +++ b/internal/controller/patch_funcs.go @@ -70,10 +70,6 @@ func (r *LightrunJavaAgentReconciler) patchDeployment(lightrunJavaAgent *agentv1 if err != nil { return err } - deploymentApplyConfig.Spec.Template.Spec.WithSecurityContext( - corev1ac.PodSecurityContext(). - WithFSGroup(1000), - ) return nil } @@ -157,10 +153,17 @@ func (r *LightrunJavaAgentReconciler) addInitContainer(deploymentApplyConfig *ap WithEnv(envVars...). WithSecurityContext( corev1ac.SecurityContext(). - WithReadOnlyRootFilesystem(true). - WithAllowPrivilegeEscalation(false). + WithCapabilities( + corev1ac.Capabilities(). + WithDrop(corev1.Capability("ALL")), + ). WithRunAsNonRoot(true). - WithRunAsUser(1000), + WithAllowPrivilegeEscalation(false). + WithReadOnlyRootFilesystem(true). + WithSeccompProfile( + corev1ac.SeccompProfile(). + WithType(corev1.SeccompProfileTypeRuntimeDefault), + ), ). WithResources( corev1ac.ResourceRequirements(). @@ -359,10 +362,17 @@ func (r *LightrunJavaAgentReconciler) addInitContainerToStatefulSet(statefulSetA WithEnv(envVars...). WithSecurityContext( corev1ac.SecurityContext(). - WithReadOnlyRootFilesystem(true). - WithAllowPrivilegeEscalation(false). + WithCapabilities( + corev1ac.Capabilities(). + WithDrop(corev1.Capability("ALL")), + ). WithRunAsNonRoot(true). - WithRunAsUser(1000), + WithAllowPrivilegeEscalation(false). + WithReadOnlyRootFilesystem(true). + WithSeccompProfile( + corev1ac.SeccompProfile(). + WithType(corev1.SeccompProfileTypeRuntimeDefault), + ), ). WithResources( corev1ac.ResourceRequirements(). @@ -392,7 +402,7 @@ func (r *LightrunJavaAgentReconciler) patchStatefulSetAppContainers(lightrunJava WithName(container.Name). WithImage(container.Image). WithVolumeMounts( - corev1ac.VolumeMount().WithName(lightrunJavaAgent.Spec.InitContainer.SharedVolumeName).WithMountPath(lightrunJavaAgent.Spec.InitContainer.SharedVolumeMountPath), + corev1ac.VolumeMount().WithMountPath(lightrunJavaAgent.Spec.InitContainer.SharedVolumeMountPath).WithName(lightrunJavaAgent.Spec.InitContainer.SharedVolumeName), ), ) } diff --git a/lightrun-init-agent/Dockerfile b/lightrun-init-agent/Dockerfile index d7aecf5..9e3fcbc 100644 --- a/lightrun-init-agent/Dockerfile +++ b/lightrun-init-agent/Dockerfile @@ -3,7 +3,7 @@ ARG base_image_tag=alpine-3.20.0-r1 FROM lightruncom/prod-base:${base_image_tag} ARG FILE -COPY $FILE /tmp/$FILE +COPY lightrun-init-agent/$FILE /tmp/$FILE RUN unzip -o /tmp/$FILE -d /agent ;\ rm -rf /tmp/$FILE && \ @@ -13,13 +13,10 @@ RUN unzip -o /tmp/$FILE -d /agent ;\ # In openshift UID will be dynamic per project, hence procide permissions to root group (defualt in k8s) chgrp -R 0 /agent && \ chmod -R g=u /agent && \ - # Set proper permissions for the agent directory - chown -R 1000:1000 /agent && \ - chmod -R 750 /agent && \ - # Create secret directory with proper permissions + # Create secret directory mkdir -p /etc/lightrun/secret && \ - chown -R 1000:1000 /etc/lightrun/secret && \ - chmod -R 700 /etc/lightrun/secret + chgrp -R 0 /etc/lightrun/secret && \ + chmod -R g=u /etc/lightrun/secret # Copy and set permissions for update_config.sh before switching user COPY update_config.sh /update_config.sh From ecdac1b1eaecb69ec1381b26fe1754bdcf8900a6 Mon Sep 17 00:00:00 2001 From: Tal Yitzhak Date: Tue, 10 Jun 2025 00:20:21 +0300 Subject: [PATCH 3/4] Resolving PR comments --- lightrun-init-agent/Dockerfile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lightrun-init-agent/Dockerfile b/lightrun-init-agent/Dockerfile index 9e3fcbc..8bd28fd 100644 --- a/lightrun-init-agent/Dockerfile +++ b/lightrun-init-agent/Dockerfile @@ -20,8 +20,7 @@ RUN unzip -o /tmp/$FILE -d /agent ;\ # Copy and set permissions for update_config.sh before switching user COPY update_config.sh /update_config.sh -RUN chmod 750 /update_config.sh && \ - chown 1000:1000 /update_config.sh +RUN chmod 750 /update_config.sh USER 1000 From 0ec4cf9d2e0621a8bb00c4abdf912a8b1f96bb29 Mon Sep 17 00:00:00 2001 From: Tal Yitzhak Date: Tue, 10 Jun 2025 09:54:39 +0300 Subject: [PATCH 4/4] Resolving PR comments --- lightrun-init-agent/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lightrun-init-agent/Dockerfile b/lightrun-init-agent/Dockerfile index 8bd28fd..35b8fad 100644 --- a/lightrun-init-agent/Dockerfile +++ b/lightrun-init-agent/Dockerfile @@ -19,7 +19,7 @@ RUN unzip -o /tmp/$FILE -d /agent ;\ chmod -R g=u /etc/lightrun/secret # Copy and set permissions for update_config.sh before switching user -COPY update_config.sh /update_config.sh +COPY lightrun-init-agent/update_config.sh /update_config.sh RUN chmod 750 /update_config.sh USER 1000