From 6cab053e6edae78ffcc74c7fdd12bb2eb6e53226 Mon Sep 17 00:00:00 2001 From: Ganeshrockz Date: Wed, 14 Jun 2023 10:01:53 +0530 Subject: [PATCH 1/2] Backport for helm audit logs --- .changelog/2369.txt | 3 + .../templates/server-config-configmap.yaml | 24 +++ .../test/unit/server-config-configmap.bats | 140 ++++++++++++++++++ charts/consul/values.yaml | 54 +++++++ 4 files changed, 221 insertions(+) create mode 100644 .changelog/2369.txt diff --git a/.changelog/2369.txt b/.changelog/2369.txt new file mode 100644 index 0000000000..35643ce272 --- /dev/null +++ b/.changelog/2369.txt @@ -0,0 +1,3 @@ +```release-note:improvement +(Consul Enterprise) Add support to provide inputs via helm for audit log related configuration +``` \ No newline at end of file diff --git a/charts/consul/templates/server-config-configmap.yaml b/charts/consul/templates/server-config-configmap.yaml index f7dd85f166..267fbe505b 100644 --- a/charts/consul/templates/server-config-configmap.yaml +++ b/charts/consul/templates/server-config-configmap.yaml @@ -1,4 +1,5 @@ {{- if (or (and (ne (.Values.server.enabled | toString) "-") .Values.server.enabled) (and (eq (.Values.server.enabled | toString) "-") .Values.global.enabled)) }} +{{- if and .Values.server.auditLogs.enabled (not .Values.global.acls.manageSystemACLs) }}{{fail "ACLs must be enabled inorder to configure audit logs"}}{{ end -}} # StatefulSet to run the actual Consul server cluster. apiVersion: v1 kind: ConfigMap @@ -178,4 +179,27 @@ data: } } {{- end }} + {{- if and .Values.server.auditLogs.enabled .Values.global.acls.manageSystemACLs }} + audit-logging.json: |- + { + "audit": { + "enabled": "true", + "sink": { + {{- range $index, $element := .Values.server.auditLogs.sinks }} + {{- if ne $index 0 }},{{end}} + "{{ $element.name }}": { + {{- $firstKeyValuePair := false }} + {{- range $k, $v := $element }} + {{- if ne $k "name" }} + {{- if ne $firstKeyValuePair false }},{{end}} + {{- $firstKeyValuePair = true }} + "{{ $k }}": "{{ $v }}" + {{- end }} + {{- end }} + } + {{- end }} + } + } + } + {{- end }} {{- end }} diff --git a/charts/consul/test/unit/server-config-configmap.bats b/charts/consul/test/unit/server-config-configmap.bats index 5e849d5a4f..6d8ce5f0ad 100755 --- a/charts/consul/test/unit/server-config-configmap.bats +++ b/charts/consul/test/unit/server-config-configmap.bats @@ -965,3 +965,143 @@ load _helpers [ "${actual}" = "true" ] } + +#-------------------------------------------------------------------- +# server.auditLogs + +@test "server/ConfigMap: server.auditLogs is disabled by default" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/server-config-configmap.yaml \ + --set 'server.auditLogs.enabled=false' \ + . | tee /dev/stderr | + yq -r '.data["audit-logging.json"]' | jq -r .audit | tee /dev/stderr) + + [ "${actual}" = "null" ] +} + +@test "server/ConfigMap: server.auditLogs is enabled but ACLs are disabled" { + cd `chart_dir` + run helm template \ + -s templates/server-config-configmap.yaml \ + --set 'server.auditLogs.enabled=true' \ + --set 'server.auditLogs.sinks[0].name=MySink' \ + --set 'server.auditLogs.sinks[0].type=file' \ + --set 'server.auditLogs.sinks[0].format=json' \ + --set 'server.auditLogs.sinks[0].delivery_guarantee=best-effort' \ + --set 'server.auditLogs.sinks[0].rotate_duration=24h' \ + --set 'server.auditLogs.sinks[0].path=/tmp/audit.json' \ + . + + [ "$status" -eq 1 ] + [[ "$output" =~ "ACLs must be enabled inorder to configure audit logs" ]] +} + +@test "server/ConfigMap: server.auditLogs is enabled without sink inputs" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/server-config-configmap.yaml \ + --set 'server.auditLogs.enabled=true' \ + --set 'global.acls.manageSystemACLs=true' \ + . | tee /dev/stderr | + yq -r '.data["audit-logging.json"]' | jq -r .audit.sink | tee /dev/stderr) + + [ "${actual}" = "{}" ] +} + +@test "server/ConfigMap: server.auditLogs is enabled with 1 sink input object" { + cd `chart_dir` + local object=$(helm template \ + -s templates/server-config-configmap.yaml \ + --set 'server.auditLogs.enabled=true' \ + --set 'global.acls.manageSystemACLs=true' \ + --set 'server.auditLogs.sinks[0].name=MySink' \ + --set 'server.auditLogs.sinks[0].type=file' \ + --set 'server.auditLogs.sinks[0].format=json' \ + --set 'server.auditLogs.sinks[0].delivery_guarantee=best-effort' \ + --set 'server.auditLogs.sinks[0].rotate_duration=24h' \ + --set 'server.auditLogs.sinks[0].path=/tmp/audit.json' \ + . | tee /dev/stderr | + yq -r '.data["audit-logging.json"]' | tee /dev/stderr) + + local actual=$(echo $object | jq -r .audit.sink.MySink.path | tee /dev/stderr) + [ "${actual}" = "/tmp/audit.json" ] + + local actual=$(echo $object | jq -r .audit.sink.MySink.delivery_guarantee | tee /dev/stderr) + [ "${actual}" = "best-effort" ] + + local actual=$(echo $object | jq -r .audit.sink.MySink.rotate_duration | tee /dev/stderr) + [ "${actual}" = "24h" ] +} + +@test "server/ConfigMap: server.auditLogs is enabled with 1 sink input object and it does not contain the name attribute" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/server-config-configmap.yaml \ + --set 'server.auditLogs.enabled=true' \ + --set 'global.acls.manageSystemACLs=true' \ + --set 'server.auditLogs.sinks[0].name=MySink' \ + --set 'server.auditLogs.sinks[0].type=file' \ + --set 'server.auditLogs.sinks[0].format=json' \ + --set 'server.auditLogs.sinks[0].delivery_guarantee=best-effort' \ + --set 'server.auditLogs.sinks[0].rotate_duration=24h' \ + --set 'server.auditLogs.sinks[0].path=/tmp/audit.json' \ + . | tee /dev/stderr | + yq -r '.data["audit-logging.json"]' | jq -r .audit.sink.name | tee /dev/stderr) + + [ "${actual}" = "null" ] +} + +@test "server/ConfigMap: server.auditLogs is enabled with multiple sink input objects" { + cd `chart_dir` + local object=$(helm template \ + -s templates/server-config-configmap.yaml \ + --set 'server.auditLogs.enabled=true' \ + --set 'global.acls.manageSystemACLs=true' \ + --set 'server.auditLogs.sinks[0].name=MySink1' \ + --set 'server.auditLogs.sinks[0].type=file' \ + --set 'server.auditLogs.sinks[0].format=json' \ + --set 'server.auditLogs.sinks[0].delivery_guarantee=best-effort' \ + --set 'server.auditLogs.sinks[0].rotate_duration=24h' \ + --set 'server.auditLogs.sinks[0].path=/tmp/audit.json' \ + --set 'server.auditLogs.sinks[1].name=MySink2' \ + --set 'server.auditLogs.sinks[1].type=file' \ + --set 'server.auditLogs.sinks[1].format=json' \ + --set 'server.auditLogs.sinks[1].delivery_guarantee=best-effort' \ + --set 'server.auditLogs.sinks[1].rotate_max_files=15' \ + --set 'server.auditLogs.sinks[1].rotate_duration=24h' \ + --set 'server.auditLogs.sinks[1].path=/tmp/audit-2.json' \ + --set 'server.auditLogs.sinks[2].name=MySink3' \ + --set 'server.auditLogs.sinks[2].type=file' \ + --set 'server.auditLogs.sinks[2].format=json' \ + --set 'server.auditLogs.sinks[2].delivery_guarantee=best-effort' \ + --set 'server.auditLogs.sinks[2].rotate_max_files=20' \ + --set 'server.auditLogs.sinks[2].rotate_duration=18h' \ + --set 'server.auditLogs.sinks[2].path=/tmp/audit-3.json' \ + . | tee /dev/stderr | + yq -r '.data["audit-logging.json"]' | tee /dev/stderr) + + local actual=$(echo $object | jq -r .audit.sink.MySink1.path | tee /dev/stderr) + [ "${actual}" = "/tmp/audit.json" ] + + local actual=$(echo $object | jq -r .audit.sink.MySink3.path | tee /dev/stderr) + [ "${actual}" = "/tmp/audit-3.json" ] + + local actual=$(echo $object | jq -r .audit.sink.MySink2.path | tee /dev/stderr) + [ "${actual}" = "/tmp/audit-2.json" ] + + local actual=$(echo $object | jq -r .audit.sink.MySink1.name | tee /dev/stderr) + [ "${actual}" = "null" ] + + local actual=$(echo $object | jq -r .audit.sink.MySink3.delivery_guarantee | tee /dev/stderr) + [ "${actual}" = "best-effort" ] + + local actual=$(echo $object | jq -r .audit.sink.MySink2.rotate_duration | tee /dev/stderr) + [ "${actual}" = "24h" ] + + local actual=$(echo $object | jq -r .audit.sink.MySink1.format | tee /dev/stderr) + [ "${actual}" = "json" ] + + local actual=$(echo $object | jq -r .audit.sink.MySink3.type | tee /dev/stderr) + [ "${actual}" = "file" ] +} \ No newline at end of file diff --git a/charts/consul/values.yaml b/charts/consul/values.yaml index 9ab4e7fbad..039225d0e6 100644 --- a/charts/consul/values.yaml +++ b/charts/consul/values.yaml @@ -1142,6 +1142,60 @@ server: # ``` # @type: string caCert: null + + # [Enterprise Only] Added in Consul 1.8, the audit object allow users to enable auditing + # and configure a sink and filters for their audit logs. Please refer to + # [audit logs](https://developer.hashicorp.com/consul/docs/enterprise/audit-logging) documentation + # for further information. + auditLogs: + # Controls whether Consul logs out each time a user performs an operation. + # global.acls.manageSystemACLs must be enabled to use this feature. + enabled: false + + # A single entry of the sink object provides configuration for the destination to which Consul + # will log auditing events. + # + # Example: + # + # ```yaml + # sinks: + # - name: My Sink + # type: file + # format: json + # path: /tmp/audit.json + # delivery_guarantee: best-effort + # rotate_duration: 24h + # rotate_max_files: 15 + # rotate_bytes: 25165824 + # + # ``` + # + # The sink object supports the following keys: + # + # - `name` - Name of the sink. + # + # - `type` - Type specifies what kind of sink this is. Currently only file sinks are available + # + # - `format` - Format specifies what format the events will be emitted with. Currently only `json` + # events are emitted. + # + # - `path` - The directory and filename to write audit events to. + # + # - `delivery_guarantee` - Specifies the rules governing how audit events are written. Consul + # only supports `best-effort` event delivery. + # + # - `mode` - The permissions to set on the audit log files. + # + # - `rotate_duration` - Specifies the interval by which the system rotates to a new log file. + # At least one of `rotate_duration` or `rotate_bytes` must be configured to enable audit logging. + # + # - `rotate_bytes` - Specifies how large an individual log file can grow before Consul rotates to a new file. + # At least one of rotate_bytes or rotate_duration must be configured to enable audit logging. + # + # - `rotate_max_files` - Defines the limit that Consul should follow before it deletes old log files. + # + # @type: array + sinks: [] # Configuration for Consul servers when the servers are running outside of Kubernetes. # When running external servers, configuring these values is recommended From c93c1881d3a6113fc5261666ce5a147c32b90f72 Mon Sep 17 00:00:00 2001 From: Ganeshrockz Date: Fri, 16 Jun 2023 21:19:45 +0530 Subject: [PATCH 2/2] Fix unit tests --- charts/consul/test/unit/server-statefulset.bats | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/charts/consul/test/unit/server-statefulset.bats b/charts/consul/test/unit/server-statefulset.bats index 73be0ce449..ad3f2d7326 100755 --- a/charts/consul/test/unit/server-statefulset.bats +++ b/charts/consul/test/unit/server-statefulset.bats @@ -686,7 +686,7 @@ load _helpers -s templates/server-statefulset.yaml \ . | tee /dev/stderr | yq -r '.spec.template.metadata.annotations."consul.hashicorp.com/config-checksum"' | tee /dev/stderr) - [ "${actual}" = 251dd23c6cc44bf8362acddc24c78440b6a65c4618785d027fae526958af5dde ] + [ "${actual}" = dc165411861bb45d37e20a0a337697336f333407f5fb29fca9252cdba652339c ] } @test "server/StatefulSet: adds config-checksum annotation when extraConfig is provided" { @@ -696,7 +696,7 @@ load _helpers --set 'server.extraConfig="{\"hello\": \"world\"}"' \ . | tee /dev/stderr | yq -r '.spec.template.metadata.annotations."consul.hashicorp.com/config-checksum"' | tee /dev/stderr) - [ "${actual}" = 473d54d05b794be1526d42ef04fdc049f4f979a75d3394c897eef149d399207d ] + [ "${actual}" = d69874f33a862f6728265246a3e38b3f64702e013ecd4afc5dcdc33d34a66954 ] } @test "server/StatefulSet: adds config-checksum annotation when config is updated" { @@ -706,7 +706,7 @@ load _helpers --set 'global.acls.manageSystemACLs=true' \ . | tee /dev/stderr | yq -r '.spec.template.metadata.annotations."consul.hashicorp.com/config-checksum"' | tee /dev/stderr) - [ "${actual}" = 6acd3761c0981d4d6194b3375b0f7a291e3927602ce7857344c26010381d3a61 ] + [ "${actual}" = 95a3d3b4816a0f183b8a9aac41ff386e659cd2a465f3030f01c5c4a2b9052a6c ] } #--------------------------------------------------------------------