diff --git a/.github/workflows/tests_data/lightrunjavaagent.yaml b/.github/workflows/tests_data/lightrunjavaagent.yaml index 6131b0b..6fccdad 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 + useSecretsAsMountedFiles: false 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 73140d5..8562cc6 100644 --- a/api/v1beta/lightrunjavaagent_types.go +++ b/api/v1beta/lightrunjavaagent_types.go @@ -93,6 +93,10 @@ type LightrunJavaAgentSpec struct { // +optional // Agent name for registration to the server AgentName string `json:"agentName,omitempty"` + + // UseSecretsAsMountedFiles determines whether to use secret values as mounted files (true) or as environment variables (false) + // +kubebuilder:default=false + UseSecretsAsMountedFiles bool `json:"useSecretsAsMountedFiles,omitempty"` } // LightrunJavaAgentStatus defines the observed state of LightrunJavaAgent diff --git a/charts/lightrun-agents/templates/java-agent-cr.yaml b/charts/lightrun-agents/templates/java-agent-cr.yaml index 648f2a0..9243a63 100644 --- a/charts/lightrun-agents/templates/java-agent-cr.yaml +++ b/charts/lightrun-agents/templates/java-agent-cr.yaml @@ -29,6 +29,9 @@ spec: secretName: {{ .name }}-secret {{- end }} serverHostname: {{ .serverHostname }} + {{- if .useSecretsAsMountedFiles }} + useSecretsAsMountedFiles: {{ .useSecretsAsMountedFiles | default false }} + {{- end }} 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 68874a2..c0e3e5c 100644 --- a/charts/lightrun-agents/values.yaml +++ b/charts/lightrun-agents/values.yaml @@ -19,6 +19,7 @@ javaAgents: [] # containerSelector: # - my-container-1 # serverHostname: 'lightrun.example.com' +# useSecretsAsMountedFiles: false # initContainer: # image: "lightruncom/k8s-operator-init-java-agent-linux:latest" # imagePullPolicy: "IfNotPresent" @@ -42,6 +43,7 @@ javaAgents: [] # containerSelector: # - my-container-2 # serverHostname: 'lightrun.example.com' +# useSecretsAsMountedFiles: false # agentPoolCredentials: # existingSecret: "my-existing-secret" # apiKey: "" @@ -69,6 +71,7 @@ javaAgents: [] # containerSelector: # - my-container-1 # serverHostname: 'lightrun.example.com' +# useSecretsAsMountedFiles: false # agentEnvVarName: '_JAVA_OPTIONS' # agentConfig: # max_log_cpu_cost: "2" @@ -100,6 +103,7 @@ javaAgents: [] # containerSelector: # - my-container-2 # serverHostname: 'lightrun.example.com' +# useSecretsAsMountedFiles: false # 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 04a3629..22de0b0 100644 --- a/charts/lightrun-operator/crds/lightrunjavaagent_crd.yaml +++ b/charts/lightrun-operator/crds/lightrunjavaagent_crd.yaml @@ -123,6 +123,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 + useSecretsAsMountedFiles: + default: false + description: UseSecretsAsMountedFiles determines whether to use secret + values as mounted files (true) or as environment variables (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 096cbb6..9e98ec6 100644 --- a/config/crd/bases/agents.lightrun.com_lightrunjavaagents.yaml +++ b/config/crd/bases/agents.lightrun.com_lightrunjavaagents.yaml @@ -124,6 +124,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 + useSecretsAsMountedFiles: + default: false + description: UseSecretsAsMountedFiles determines whether to use secret + values as mounted files (true) or as environment variables (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..7d0098b 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 + useSecretsAsMountedFiles: false agentEnvVarName: JAVA_TOOL_OPTIONS agentConfig: max_log_cpu_cost: "2" diff --git a/config/samples/operator.yaml b/config/samples/operator.yaml index 230b38d..93585ae 100644 --- a/config/samples/operator.yaml +++ b/config/samples/operator.yaml @@ -135,6 +135,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 + useSecretsAsMountedFiles: + default: false + description: UseSecretsAsMountedFiles determines whether to use secret + values as mounted files (true) or as environment variables (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 040698b..a19463c 100644 --- a/docs/custom_resource.md +++ b/docs/custom_resource.md @@ -51,6 +51,9 @@ spec: # If container not mentioned here it will be not patched containerSelector: - app + # useSecretsAsMountedFiles determines whether to use secret values as environment variables (false) or as mounted files (true) + # Default is false for backward compatibility + useSecretsAsMountedFiles: false --- apiVersion: v1 metadata: diff --git a/examples/lightrunjavaagent.yaml b/examples/lightrunjavaagent.yaml index 671e87f..eece6dc 100644 --- a/examples/lightrunjavaagent.yaml +++ b/examples/lightrunjavaagent.yaml @@ -61,3 +61,7 @@ spec: - latest # Agent name. If not provided, pod name will be used #agentName: "operator-test-agent" + + # UseSecretsAsMountedFiles determines whether to use secret values as mounted files (true) or as environment variables (false) + # Default is false for better security practices + useSecretsAsMountedFiles: false diff --git a/examples/operator.yaml b/examples/operator.yaml index 0c0d456..e0056b4 100644 --- a/examples/operator.yaml +++ b/examples/operator.yaml @@ -125,6 +125,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 + useSecretsAsMountedFiles: + default: false + description: UseSecretsAsMountedFiles determines whether to use secret + values as mounted files (true) or as environment variables (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 202088f..bfd6370 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, @@ -76,15 +74,13 @@ func (r *LightrunJavaAgentReconciler) patchDeployment(lightrunJavaAgent *agentv1 } 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,37 +91,84 @@ func (r *LightrunJavaAgentReconciler) addVolume(deploymentApplyConfig *appsv1ac. corev1ac.KeyToPath().WithKey("metadata").WithPath("agent.metadata.json"), ), ), - ) + } + + // Add secret volume if UseSecretsAsMountedFiles is true + if lightrunJavaAgent.Spec.UseSecretsAsMountedFiles { + 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) { spec := lightrunJavaAgent.Spec isImagePullPolicyConfigured := spec.InitContainer.ImagePullPolicy != "" - initContainerApplyConfig := corev1ac.Container(). - WithName(initContainerName). - WithImage(spec.InitContainer.Image). - WithVolumeMounts( - corev1ac.VolumeMount().WithName(spec.InitContainer.SharedVolumeName).WithMountPath("/tmp/"), - corev1ac.VolumeMount().WithName(cmVolumeName).WithMountPath("/tmp/cm/"), - ).WithEnv( - corev1ac.EnvVar().WithName("LIGHTRUN_KEY").WithValueFrom( - corev1ac.EnvVarSource().WithSecretKeyRef( - corev1ac.SecretKeySelector().WithName(secret.Name).WithKey("lightrun_key"), + + // Always mount shared and config volumes + volumeMounts := []*corev1ac.VolumeMountApplyConfiguration{ + corev1ac.VolumeMount().WithName(spec.InitContainer.SharedVolumeName).WithMountPath("/tmp/"), + corev1ac.VolumeMount().WithName(cmVolumeName).WithMountPath("/tmp/cm/"), + } + // If using mounted files, mount the secret as a volume + if spec.UseSecretsAsMountedFiles { + volumeMounts = append(volumeMounts, + corev1ac.VolumeMount().WithName("lightrun-secret").WithMountPath("/etc/lightrun/secret").WithReadOnly(true), + ) + } + + // Always set LIGHTRUN_SERVER + envVars := []*corev1ac.EnvVarApplyConfiguration{ + corev1ac.EnvVar().WithName("LIGHTRUN_SERVER").WithValue(spec.ServerHostname), + } + // If not using mounted files, set LIGHTRUN_KEY and PINNED_CERT from secret as env vars + if !spec.UseSecretsAsMountedFiles { + envVars = append(envVars, + corev1ac.EnvVar().WithName("LIGHTRUN_KEY").WithValueFrom( + corev1ac.EnvVarSource().WithSecretKeyRef( + corev1ac.SecretKeySelector().WithName(secret.Name).WithKey("lightrun_key"), + ), ), - ), - corev1ac.EnvVar().WithName("PINNED_CERT").WithValueFrom( - corev1ac.EnvVarSource().WithSecretKeyRef( - corev1ac.SecretKeySelector().WithName(secret.Name).WithKey("pinned_cert_hash"), + corev1ac.EnvVar().WithName("PINNED_CERT").WithValueFrom( + corev1ac.EnvVarSource().WithSecretKeyRef( + corev1ac.SecretKeySelector().WithName(secret.Name).WithKey("pinned_cert_hash"), + ), ), - ), - corev1ac.EnvVar().WithName("LIGHTRUN_SERVER").WithValue(spec.ServerHostname), - ). + ) + } + + initContainer := corev1ac.Container(). + WithName(initContainerName). + WithImage(spec.InitContainer.Image). + WithVolumeMounts(volumeMounts...). + WithEnv(envVars...). + WithSecurityContext( + corev1ac.SecurityContext(). + WithCapabilities( + corev1ac.Capabilities().WithDrop(corev1.Capability("ALL")), + ). + WithRunAsNonRoot(true). + WithAllowPrivilegeEscalation(false). + WithSeccompProfile( + corev1ac.SeccompProfile(). + WithType(corev1.SeccompProfileTypeRuntimeDefault), + ), + ). WithResources( corev1ac.ResourceRequirements(). WithLimits( corev1.ResourceList{ corev1.ResourceCPU: *resource.NewMilliQuantity(int64(50), resource.BinarySI), - corev1.ResourceMemory: *resource.NewScaledQuantity(int64(64), resource.Scale(6)), // 500 * 10^6 = 500M + corev1.ResourceMemory: *resource.NewScaledQuantity(int64(64), resource.Scale(6)), // 64M }, ).WithRequests( corev1.ResourceList{ @@ -133,23 +176,11 @@ 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), - ), ) if isImagePullPolicyConfigured { - initContainerApplyConfig.WithImagePullPolicy(spec.InitContainer.ImagePullPolicy) + initContainer.WithImagePullPolicy(spec.InitContainer.ImagePullPolicy) } - deploymentApplyConfig.Spec.Template.Spec.WithInitContainers(initContainerApplyConfig) + deploymentApplyConfig.Spec.Template.Spec.WithInitContainers(initContainer) } func (r *LightrunJavaAgentReconciler) patchAppContainers(lightrunJavaAgent *agentv1beta.LightrunJavaAgent, origDeployment *appsv1.Deployment, deploymentApplyConfig *appsv1ac.DeploymentApplyConfiguration) error { @@ -233,8 +264,7 @@ func (r *LightrunJavaAgentReconciler) patchStatefulSet(lightrunJavaAgent *agentv corev1ac.PodSpec(), ).WithAnnotations(map[string]string{ annotationConfigMapHash: fmt.Sprint(cmDataHash), - }, - ), + }), ), ).WithAnnotations(map[string]string{ annotationAgentName: lightrunJavaAgent.Name, @@ -242,10 +272,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 { @@ -256,14 +284,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( @@ -274,31 +301,78 @@ func (r *LightrunJavaAgentReconciler) addVolumeToStatefulSet(statefulSetApplyCon corev1ac.KeyToPath().WithKey("metadata").WithPath("agent.metadata.json"), ), ), - ) + } + + // Add secret volume if UseSecretsAsMountedFiles is true + if lightrunJavaAgent.Spec.UseSecretsAsMountedFiles { + 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) { spec := lightrunJavaAgent.Spec isImagePullPolicyConfigured := spec.InitContainer.ImagePullPolicy != "" - initContainerApplyConfig := corev1ac.Container(). - WithName(initContainerName). - WithImage(spec.InitContainer.Image). - WithVolumeMounts( - corev1ac.VolumeMount().WithName(spec.InitContainer.SharedVolumeName).WithMountPath("/tmp/"), - corev1ac.VolumeMount().WithName(cmVolumeName).WithMountPath("/tmp/cm/"), - ).WithEnv( - corev1ac.EnvVar().WithName("LIGHTRUN_KEY").WithValueFrom( - corev1ac.EnvVarSource().WithSecretKeyRef( - corev1ac.SecretKeySelector().WithName(secret.Name).WithKey("lightrun_key"), + + // Always mount shared and config volumes + volumeMounts := []*corev1ac.VolumeMountApplyConfiguration{ + corev1ac.VolumeMount().WithName(spec.InitContainer.SharedVolumeName).WithMountPath("/tmp/"), + corev1ac.VolumeMount().WithName(cmVolumeName).WithMountPath("/tmp/cm/"), + } + // If using mounted files, mount the secret as a volume + if spec.UseSecretsAsMountedFiles { + volumeMounts = append(volumeMounts, + corev1ac.VolumeMount().WithName("lightrun-secret").WithMountPath("/etc/lightrun/secret").WithReadOnly(true), + ) + } + + // Always set LIGHTRUN_SERVER + envVars := []*corev1ac.EnvVarApplyConfiguration{ + corev1ac.EnvVar().WithName("LIGHTRUN_SERVER").WithValue(spec.ServerHostname), + } + // If not using mounted files, set LIGHTRUN_KEY and PINNED_CERT from secret as env vars + if !spec.UseSecretsAsMountedFiles { + envVars = append(envVars, + corev1ac.EnvVar().WithName("LIGHTRUN_KEY").WithValueFrom( + corev1ac.EnvVarSource().WithSecretKeyRef( + corev1ac.SecretKeySelector().WithName(secret.Name).WithKey("lightrun_key"), + ), ), - ), - corev1ac.EnvVar().WithName("PINNED_CERT").WithValueFrom( - corev1ac.EnvVarSource().WithSecretKeyRef( - corev1ac.SecretKeySelector().WithName(secret.Name).WithKey("pinned_cert_hash"), + corev1ac.EnvVar().WithName("PINNED_CERT").WithValueFrom( + corev1ac.EnvVarSource().WithSecretKeyRef( + corev1ac.SecretKeySelector().WithName(secret.Name).WithKey("pinned_cert_hash"), + ), ), - ), - corev1ac.EnvVar().WithName("LIGHTRUN_SERVER").WithValue(spec.ServerHostname), - ). + ) + } + + initContainer := corev1ac.Container(). + WithName(initContainerName). + WithImage(spec.InitContainer.Image). + WithVolumeMounts(volumeMounts...). + WithEnv(envVars...). + WithSecurityContext( + corev1ac.SecurityContext(). + WithCapabilities( + corev1ac.Capabilities().WithDrop(corev1.Capability("ALL")), + ). + WithRunAsNonRoot(true). + WithAllowPrivilegeEscalation(false). + WithSeccompProfile( + corev1ac.SeccompProfile(). + WithType(corev1.SeccompProfileTypeRuntimeDefault), + ), + ). WithResources( corev1ac.ResourceRequirements(). WithLimits( @@ -312,23 +386,11 @@ 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), - ), ) if isImagePullPolicyConfigured { - initContainerApplyConfig.WithImagePullPolicy(spec.InitContainer.ImagePullPolicy) + initContainer.WithImagePullPolicy(spec.InitContainer.ImagePullPolicy) } - statefulSetApplyConfig.Spec.Template.Spec.WithInitContainers(initContainerApplyConfig) + statefulSetApplyConfig.Spec.Template.Spec.WithInitContainers(initContainer) } func (r *LightrunJavaAgentReconciler) patchStatefulSetAppContainers(lightrunJavaAgent *agentv1beta.LightrunJavaAgent, origStatefulSet *appsv1.StatefulSet, statefulSetApplyConfig *appsv1ac.StatefulSetApplyConfiguration) error { diff --git a/lightrun-init-agent/Dockerfile b/lightrun-init-agent/Dockerfile index b2dc3d3..35b8fad 100644 --- a/lightrun-init-agent/Dockerfile +++ b/lightrun-init-agent/Dockerfile @@ -1,7 +1,7 @@ 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 @@ -12,9 +12,16 @@ 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 && \ + # Create secret directory + mkdir -p /etc/lightrun/secret && \ + chgrp -R 0 /etc/lightrun/secret && \ + chmod -R g=u /etc/lightrun/secret -USER 1000 +# Copy and set permissions for update_config.sh before switching user COPY lightrun-init-agent/update_config.sh /update_config.sh +RUN chmod 750 /update_config.sh + +USER 1000 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