Skip to content

Commit b38231d

Browse files
feat(lmlogs): user defined secret support for lmlogs (#541)
* feat(lmlogs): userDefinedSecret support for lmlogs * feat(lmlogs): incrementing the chart version for logs * feat(lmlogs): minor changes for adding chart validations * feat(lmlogs): fixing linting error * feat(lmlogs): lint validation fixes * feat(lmlogs): adding default value for authMode and reerting image tag
1 parent ddc3aaf commit b38231d

File tree

8 files changed

+297
-23
lines changed

8 files changed

+297
-23
lines changed

charts/lm-logs/Chart.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
apiVersion: v2
22
description: A Helm chart for sending k8s logs to Logic Monitor
33
name: lm-logs
4-
version: 0.8.0-rc01
4+
version: 0.9.0-rc01
55
maintainers:
66
- email: dev@logicmonitor.com
77
name: LogicMonitor

charts/lm-logs/README.md

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,20 @@ helm install -n <namespace> \
1616
lm-logs logicmonitor/lm-logs
1717
```
1818

19+
Install the lm-logs chart using a user defined secret for LM credentials.
20+
21+
``` console
22+
# For LMv1
23+
helm install lm-logs logicmonitor/lm-logs -n <namespace> \
24+
--set global.userDefinedSecret=lm-logs-credentials \
25+
--set authMode=lmv1
26+
27+
# For Bearer
28+
helm install lm-logs logicmonitor/lm-logs -n <namespace> \
29+
--set global.userDefinedSecret=lm-logs-credentials \
30+
--set authMode=bearer
31+
```
32+
1933
#### Parameters
2034
The following tables lists the configurable parameters of the lm-logs chart and their default values.
2135
| Parameter | Description | Default |
@@ -24,9 +38,11 @@ The following tables lists the configurable parameters of the lm-logs chart and
2438
| `global.nameOverride` | Global storage class for dynamic provisioning | `""` |
2539
| `global.fullnameOverride` | Global storage class for dynamic provisioning | `""` |
2640
| `global.lm_company_name` | LogicMonitor account name | `nil` |
27-
| `global.lm_company_domain` | LogicMonitor company domain name | `logicmonitor.com` |
41+
| `global.userDefinedSecret` | User Defined Secret for LM credentials | `""` |
42+
| `global.lm_company_domain` | LogicMonitor company domain name | `logicmonitor.com` |
2843
| `global.lm_access_id` | LogicMonitor API Token Access ID | `nil` |
2944
| `global.lm_access_key` | LogicMonitor API Token Access Key | `nil` |
45+
| `authMode` | Mode to use for authenticating requests sent to LM. Can we lmv1/bearer | `lmv1` |
3046
| `image.repository` | Container image repository | `logicmonitor/lm-logs-k8s-fluentd` |
3147
| `image.pullPolicy` | Container image pull policy | `IfNotPresent` |
3248
| `image.tag` | Container image tag | `""` |
@@ -61,6 +77,14 @@ For descriptions see: https://github.com/fabric8io/fluent-plugin-kubernetes_meta
6177
* FLUENT_KUBERNETES_METADATA_SKIP_MASTER_URL
6278
* FLUENT_KUBERNETES_METADATA_SKIP_NAMESPACE_METADATA
6379

80+
#### User Defined Secret for LM credentials
81+
You can create a kubernetes secret with your LM credentials and pass the secret name to the chart.
82+
The secret must contain the following keys:
83+
- account
84+
- accessID
85+
- accessKey
86+
- bearerToken (if accessKey/accessID is not present in the secret)
87+
Also, the authMode needs to be set accordingly. If the secret contains accessID/accessKey, authMode should be set to lmv1, otherwise bearer (similarly it should be set for the configurable parameters).
6488
#### New deviceless logs k8s integration (beta)
6589
Note: This feature may not be available to all customers.
6690
To enable this feature set `fluent.device_less_logs=true`
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
11
lm_company_name: "dummy_company"
22
lm_access_id: "dummy_id"
33
lm_access_key: "dummy_key"
4+
authMode: "lmv1"
5+
global:
6+
account: "dummyaccount"
7+
accessID: "dummyid"
8+
accessKey: "dummykey"

charts/lm-logs/templates/_helpers.tpl

Lines changed: 165 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,111 @@ If release name contains chart name it will be used as a full name.
2323
{{- end }}
2424
{{- end }}
2525

26+
27+
{{/*
28+
Did the user set global.userDefinedSecret?
29+
*/}}
30+
{{- define "lm-logs.userSecretSet" -}}
31+
{{- if .Values.global.userDefinedSecret }}true{{ end -}}
32+
{{- end -}}
33+
34+
{{/*
35+
Return the credentials Secret name:
36+
- If global.userDefinedSecret is provided, use that.
37+
- Otherwise fall back to <fullname>-creds.
38+
*/}}
39+
{{- define "lm-logs.credsSecretName" -}}
40+
{{- if .Values.global.userDefinedSecret -}}
41+
{{- .Values.global.userDefinedSecret -}}
42+
{{- else -}}
43+
{{- printf "%s-creds" (include "fluentd.fullname" .) -}}
44+
{{- end -}}
45+
{{- end -}}
46+
47+
{{/* True if we have any creds in any source (used by template fail-guard) */}}
48+
{{- define "lm-logs.credsProvided" -}}
49+
{{- $uds := default "" .Values.global.userDefinedSecret -}}
50+
{{- $ga := default "" .Values.global.accessID -}}
51+
{{- $gk := default "" .Values.global.accessKey -}}
52+
{{- $va := default "" .Values.lm_access_id -}}
53+
{{- $vk := default "" .Values.lm_access_key -}}
54+
{{- $vb := default "" .Values.lm_bearer_token -}}
55+
{{- if or (ne $uds "")
56+
(and (ne $ga "") (ne $gk ""))
57+
(and (ne $va "") (ne $vk ""))
58+
(ne $vb "") -}}true{{- end -}}
59+
{{- end -}}
60+
61+
{{/*
62+
Emit a secretKeyRef block given a key name.
63+
Usage:
64+
{{ include "lm-logs.secretKeyRef" (dict "ctx" . "key" "bearerToken") | nindent 10 }}
65+
*/}}
66+
{{- define "lm-logs.secretKeyRef" -}}
67+
name: {{ include "lm-logs.credsSecretName" .ctx }}
68+
key: {{ .key }}
69+
optional: true
70+
{{- end -}}
71+
72+
{{/* Validate credentials + account at render time */}}
73+
{{- define "lm-logs.assertInputs" -}}
74+
{{- $ns := .Release.Namespace -}}
75+
{{- $mode := default "" .Values.authMode -}}
76+
{{- $uds := default "" .Values.global.userDefinedSecret -}}
77+
78+
{{- /* Fetch Secret if configured */ -}}
79+
{{- $sec := dict -}}
80+
{{- if ne $uds "" -}}
81+
{{- $sec = lookup "v1" "Secret" $ns $uds | default dict -}}
82+
{{- if not $sec }}
83+
{{- fail (printf "global.userDefinedSecret=%q not found in namespace %q" $uds $ns) -}}
84+
{{- end -}}
85+
{{- end -}}
86+
87+
{{- /* Helper: what keys exist in Secret? */ -}}
88+
{{- $hasSecKey := (and (ne $uds "")
89+
$sec.data
90+
(kindIs "map" $sec.data)) -}}
91+
{{- $secHas := dict -}}
92+
{{- if $hasSecKey -}}
93+
{{- $_ := set $secHas "account" (hasKey $sec.data "account") -}}
94+
{{- $_ := set $secHas "accessID" (hasKey $sec.data "accessID") -}}
95+
{{- $_ := set $secHas "accessKey" (hasKey $sec.data "accessKey") -}}
96+
{{- $_ := set $secHas "bearerToken" (hasKey $sec.data "bearerToken") -}}
97+
{{- end -}}
98+
99+
{{- /* 1) Enforce account name presence (values OR global OR Secret) */ -}}
100+
{{- $hasAccount := or
101+
(ne (default "" .Values.lm_company_name) "")
102+
(ne (default "" .Values.global.account) "")
103+
(and (ne $uds "") ($secHas.account | default false)) -}}
104+
{{- if not $hasAccount -}}
105+
{{- fail "Account name missing: set lm_company_name or global.account, or provide Secret with key 'account' via global.userDefinedSecret." -}}
106+
{{- end -}}
107+
108+
{{- /* 2) Enforce credentials per authMode */ -}}
109+
{{- if eq $mode "lmv1" -}}
110+
{{- $haslmv1FromSecret := and (ne $uds "") ($secHas.accessID | default false) ($secHas.accessKey | default false) -}}
111+
{{- $haslmv1FromGlobal := and (ne (default "" .Values.global.accessID) "")
112+
(ne (default "" .Values.global.accessKey) "") -}}
113+
{{- $haslmv1FromValues := and (ne (default "" .Values.lm_access_id) "")
114+
(ne (default "" .Values.lm_access_key) "") -}}
115+
{{- if not (or $haslmv1FromSecret $haslmv1FromGlobal $haslmv1FromValues) -}}
116+
{{- fail "LM v1 auth selected (authMode=lmv1) but no lmv1 found. Provide either: Secret with 'accessID'+'accessKey', or global.accessID+global.accessKey, or lm_access_id+lm_access_key." -}}
117+
{{- end -}}
118+
119+
{{- else if eq $mode "bearer" -}}
120+
{{- $hasBearerFromSecret := and (ne $uds "") ($secHas.bearerToken | default false) -}}
121+
{{- $hasBearerFromValues := ne (default "" .Values.lm_bearer_token) "" -}}
122+
{{- if not (or $hasBearerFromSecret $hasBearerFromValues) -}}
123+
{{- fail "Bearer auth selected (authMode=bearer) but no token found. Provide either: Secret with 'bearerToken' or lm_bearer_token in values." -}}
124+
{{- end -}}
125+
126+
{{- else -}}
127+
{{- fail "authMode must be 'lmv1' or 'bearer'." -}}
128+
{{- end -}}
129+
{{- end -}}
130+
26131
{{/*
27132
Adding validations for clustername for lm-logs to contain only lower alphanumeric or '-' and start and end with an alphanumeric character
28133
*/}}
@@ -43,7 +148,8 @@ kubernetes.cluster_name {{ $cluster }}
43148
{{- end }}
44149

45150
{{/*
46-
User-agent for log-ingest requests */}}
151+
User-agent for log-ingest requests
152+
*/}}
47153
{{- define "logsource.userAgent" -}}
48154
{{- $cluster := "" -}}
49155
{{- if .Values.kubernetes.cluster_name -}}
@@ -131,24 +237,71 @@ Return the appropriate apiVersion for rbac.
131237
"{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
132238
{{- end -}}
133239

240+
{{/*
241+
Emit auth lines. If .Values.authMode is set, honor it; else use auto priority.
242+
Auto priority: Secret(lmv1) → global lmv1 → values lmv1 → values bearer
243+
*/}}
244+
{{- define "lm-logs.authBlock" -}}
245+
{{- $mode := default "" .Values.authMode -}}
246+
{{- $uds := default "" .Values.global.userDefinedSecret -}}
247+
{{- $ga := default "" .Values.global.accessID -}}
248+
{{- $gk := default "" .Values.global.accessKey -}}
249+
{{- $va := default "" .Values.lm_access_id -}}
250+
{{- $vk := default "" .Values.lm_access_key -}}
251+
{{- $vb := default "" .Values.lm_bearer_token -}}
252+
253+
{{- if eq $mode "lmv1" -}}
254+
{{- if ne $uds "" -}}
255+
access_id "#{ENV['LM_ACCESS_ID']}"
256+
access_key "#{ENV['LM_ACCESS_KEY']}"
257+
{{- else if and (ne $ga "") (ne $gk "") -}}
258+
access_id {{ $ga | quote }}
259+
access_key {{ $gk | quote }}
260+
{{- else if and (ne $va "") (ne $vk "") -}}
261+
access_id {{ $va | quote }}
262+
access_key {{ $vk | quote }}
263+
{{- end -}}
264+
265+
{{- else if eq $mode "bearer" -}}
266+
{{- if ne $uds "" -}}
267+
bearer_token "#{ENV['LM_BEARER_TOKEN']}"
268+
{{- else if ne $vb "" -}}
269+
bearer_token {{ $vb | quote }}
270+
{{- end -}}
271+
272+
{{- else -}}
273+
{{- if ne $uds "" -}}
274+
access_id "#{ENV['LM_ACCESS_ID']}"
275+
access_key "#{ENV['LM_ACCESS_KEY']}"
276+
{{- else if and (ne $ga "") (ne $gk "") -}}
277+
access_id {{ $ga | quote }}
278+
access_key {{ $gk | quote }}
279+
{{- else if and (ne $va "") (ne $vk "") -}}
280+
access_id {{ $va | quote }}
281+
access_key {{ $vk | quote }}
282+
{{- else if ne $vb "" -}}
283+
bearer_token {{ $vb | quote }}
284+
{{- end -}}
285+
{{- end -}}
286+
{{- end -}}
287+
288+
{{/*
289+
Fluentd <match> block with company_name priority:
290+
ENV['LM_ACCOUNT'] → global.account → lm_company_name
291+
*/}}
134292
{{- define "fluentd.lmMatch" -}}
135293
<match {{ .tag }}>
136294
@type lm
137-
company_name {{ if .context.Values.lm_company_name }}{{ .context.Values.lm_company_name }}{{ else }}{{ required "A valid .Values.lm_company_name or .Values.global.account entry is required!" .context.Values.global.account }}{{ end }}
295+
{{ $fb := .context.Values.global.account | default .context.Values.lm_company_name | default "" }}
296+
company_name "#{ENV['LM_ACCOUNT'].to_s != '' ? ENV['LM_ACCOUNT'] : '{{ $fb }}'}"
138297
company_domain {{ .context.Values.lm_company_domain | default .context.Values.global.companyDomain | default "logicmonitor.com" }}
139298
resource_mapping '{{ .resource_mapping }}'
140-
resource_type {{ .context.Values.fluent.resource_type | default "" }}
141-
{{- if and (or .context.Values.lm_access_id .context.Values.global.accessID) (or .context.Values.lm_access_key .context.Values.global.accessKey) }}
142-
access_id {{ .context.Values.lm_access_id | default .context.Values.global.accessID }}
143-
access_key {{ .context.Values.lm_access_key | default .context.Values.global.accessKey }}
144-
{{- else if .context.Values.lm_bearer_token }}
145-
bearer_token {{ .context.Values.lm_bearer_token }}
146-
{{- else }}
147-
{{ required "Either specify valid lm_access_id and lm_access_key both or lm_bearer_token for authentication with LogicMonitor." .context.Values.lm_bearer_token }}
148-
{{- end }}
299+
resource_type {{ .context.Values.fluent.resource_type | default "k8s" }}
300+
{{ include "lm-logs.authBlock" .context | nindent 2 }}
301+
149302
debug false
150303
compression gzip
151-
{{ include "logsource.userAgent" .context | nindent 8 }}
304+
{{ include "logsource.userAgent" .context }}
152305
include_metadata {{ hasKey .context.Values.fluent "include_metadata" | ternary .context.Values.fluent.include_metadata true }}
153306
device_less_logs {{ .context.Values.fluent.device_less_logs | default false }}
154307
<buffer>

charts/lm-logs/templates/configmap.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
{{- /* Accept any of: userDefinedSecret, bearerToken value, or id+key values */ -}}
2+
{{- if not (include "lm-logs.credsProvided" .) -}}
3+
{{- fail "Provide credentials via Secret (global.userDefinedSecret) or via global.* / lm_* values." -}}
4+
{{- end -}}
5+
{{- include "lm-logs.assertInputs" . -}}
16
kind: ConfigMap
27
apiVersion: v1
38
metadata:

charts/lm-logs/templates/deamonset.yaml

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,25 @@ spec:
3131
valueFrom:
3232
fieldRef:
3333
fieldPath: spec.nodeName
34-
{{ if gt (.Values.env | len) 0 }}
35-
{{ include "ds-env" . | nindent 12 }}
36-
{{ end }}
34+
{{- if gt (len .Values.env) 0 }}
35+
{{- include "ds-env" . | nindent 12 }}
36+
{{- end }}
37+
- name: LM_ACCOUNT
38+
valueFrom:
39+
secretKeyRef:
40+
{{- include "lm-logs.secretKeyRef" (dict "ctx" . "key" "account") | nindent 18 }}
41+
- name: LM_ACCESS_ID
42+
valueFrom:
43+
secretKeyRef:
44+
{{- include "lm-logs.secretKeyRef" (dict "ctx" . "key" "accessID") | nindent 18 }}
45+
- name: LM_ACCESS_KEY
46+
valueFrom:
47+
secretKeyRef:
48+
{{- include "lm-logs.secretKeyRef" (dict "ctx" . "key" "accessKey") | nindent 18 }}
49+
- name: LM_BEARER_TOKEN
50+
valueFrom:
51+
secretKeyRef:
52+
{{- include "lm-logs.secretKeyRef" (dict "ctx" . "key" "bearerToken") | nindent 18 }}
3753
imagePullPolicy: {{ .Values.image.pullPolicy | default "Always" }}
3854
resources:
3955
{{- toYaml .Values.resources | nindent 12 }}

charts/lm-logs/values.schema.json

Lines changed: 67 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,15 @@
165165
""
166166
],
167167
"$comment": "ui:clusterName-ignore tf:"
168+
},
169+
"userDefinedSecret": {
170+
"type": "string",
171+
"title": "Existing Kubernetes Secret name",
172+
"description": "Name of a Secret that contains credentials for lm-logs. Expected keys: 'account' and either ('accessID' + 'accessKey') or 'bearerToken'.",
173+
"default": "",
174+
"examples": [
175+
"lm-logs-credentials"
176+
]
168177
}
169178
}
170179
},
@@ -427,13 +436,67 @@
427436
"type": "boolean",
428437
"default": true,
429438
"description": "If true and no custom systemd.conf is provided, a default configuration for systemd will be injected. If false, systemd will be disabled regardless of conf."
439+
},
440+
"authMode": {
441+
"description": "If bearer then will use bearerToken if set, if lmv1 will use accessID/accessKey if set.",
442+
"oneOf": [
443+
{ "enum": ["bearer", "lmv1"] },
444+
{ "type": "string", "maxLength": 0 }
445+
]
430446
}
431447
},
432448
"additionalProperties": false,
433-
"required": [
434-
"lm_access_id",
435-
"lm_access_key",
436-
"lm_company_name"
449+
450+
"required": ["authMode"],
451+
452+
"allOf": [
453+
{
454+
"anyOf": [
455+
{ "required": ["lm_bearer_token"] },
456+
{ "required": ["lm_access_id", "lm_access_key"] },
457+
{
458+
"required": ["global"],
459+
"properties": {
460+
"global": {
461+
"type": "object",
462+
"required": ["userDefinedSecret"]
463+
}
464+
}
465+
},
466+
{
467+
"required": ["global"],
468+
"properties": {
469+
"global": {
470+
"type": "object",
471+
"required": ["accessID", "accessKey"]
472+
}
473+
}
474+
}
475+
]
476+
},
477+
{
478+
"anyOf": [
479+
{ "required": ["lm_company_name"] },
480+
{
481+
"required": ["global"],
482+
"properties": {
483+
"global": {
484+
"type": "object",
485+
"required": ["account"]
486+
}
487+
}
488+
},
489+
{
490+
"required": ["global"],
491+
"properties": {
492+
"global": {
493+
"type": "object",
494+
"required": ["userDefinedSecret"]
495+
}
496+
}
497+
}
498+
]
499+
}
437500
],
438501
"definitions": {
439502
"io.k8s.apimachinery.pkg.api.resource.Quantity": {

0 commit comments

Comments
 (0)