Add ability to control owner:group and permissions

via new module 'perm'

1) DaemonSet
2) Secret (instead of old ConfigMap)
3) Include module /bin/_perm.sh.tpl
4) Commented example in values.yaml
5) Demo: https://asciinema.org/a/209509
6) Increased # of expected DaemonSets
7) Rebased after a few merges
8) Addressing comments
9) Migrated from ConfigMap to Secret
10) Got rid of 'eval'
11) Test
12) Demo for host targeting: https://asciinema.org/a/213125

Change-Id: Ia3181dcb7fc1ccc7422c635b010000f6d3fbcf4d
This commit is contained in:
skovaleff 2018-10-31 18:22:39 -07:00
parent 97bcc9760f
commit 0731ac5d3a
5 changed files with 373 additions and 2 deletions

View File

@ -0,0 +1,135 @@
#!/bin/bash
{{/*
# Copyright 2018 AT&T Intellectual Property. All other rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
*/}}
set -e
cat <<'EOF' > {{ .Values.conf.chroot_mnt_path | quote }}/tmp/perm_host.sh
{{ include "divingbell.shcommon" . }}
backup_path='/var/divingbell/perm'
[ ! -d "${backup_path}" ] && mkdir -p "${backup_path}"
write_test "${backup_path}"
add_perm(){
# accepts $path, $owner, $group, $permissions
local path="${1}"
for i in ${path}; do
add_single_perm $i ${2} ${3} ${4}
done
}
add_single_perm(){
# accepts $path, $owner, $group, $permissions
local path="${1}"
local owner="${2}"
local group="${3}"
local permissions="${4}"
# check if file exists
[ -e $path ] || return 1
# if set -e is set the entire script will exit
# construct backup name
local file_name=$(systemd-escape $path)
local backup_file="${backup_path}/${file_name}"
# check if backup exists
if [ ! -e ${backup_file} ]; then
# Try reading the current permissions and owner
local o_owner="$(stat -c %U ${path})"
local o_group="$(stat -c %G ${path})"
local o_permissions="$(stat -c %a ${path})"
# write restore script/data
# design decision:
# we could write complete script to restore originals
# but for security reasons write only data
# otherwise we would execute _any_ script from backup dir
# chmod o_permissions path
echo "$o_permissions $path"> ${backup_file}
# chown o_owner:o_group path
echo "$o_owner:$o_group $path">> ${backup_file}
log.DEBUG ${backup_file}
fi
# apply permissions
chmod ${permissions} ${path}
# apply owner and group
chown ${owner}:${group} ${path}
# notice applied perm
applied_perm="${applied_perm}${file_name}"$'\n'
# ("${file_name}"$'\n')
}
{{- range $perm := .Values.conf.perm }}
add_perm {{ $perm.path | squote }} {{ $perm.owner | squote }} {{ $perm.group | squote }} {{ $perm.permissions | squote }}
{{- end }}
log.INFO "Applied: ${applied_perm}"
# Revert
prev_files="$(find "${backup_path}" -type f)"
if [ -n "${prev_files}" ]; then
basename -a ${prev_files} | sort > /tmp/prev_perm
echo "${applied_perm}" | sort > /tmp/curr_perm
log.DEBUG /tmp/prev_perm
log.DEBUG /tmp/curr_perm
revert_list="$(comm -23 /tmp/prev_perm /tmp/curr_perm)"
IFS=$'\n'
for o_perm in ${revert_list}; do
first=1
while IFS=' ' read -r a1 a2; do
if [ "$first" -eq 1 ]; then
$(chmod $a1 $a2)
first=0
else
$(chown $a1 $a2)
fi
done < "${backup_path}/${o_perm}"
rm "${backup_path}/${o_perm}"
log.INFO "Reverted permissions and owner: ${backup_path}/${o_perm}"
done
fi
if [ -n "${curr_settings}" ]; then
log.INFO 'All permissions successfully applied on this node.'
else
log.WARN 'No permissions overrides defined for this node.'
fi
exit 0
EOF
chmod 755 {{ .Values.conf.chroot_mnt_path | quote }}/tmp/perm_host.sh
chroot {{ .Values.conf.chroot_mnt_path | quote }} /tmp/perm_host.sh
sleep 1
echo 'INFO Putting the daemon to sleep.'
while [ 1 ]; do
sleep 300
done
exit 0

View File

@ -0,0 +1,71 @@
{{/*
# Copyright 2017 AT&T Intellectual Property. All other rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
*/}}
{{- define "divingbell.daemonset.perm" }}
{{- $daemonset := index . 0 }}
{{- $secretName := index . 1 }}
{{- $envAll := index . 2 }}
{{- with $envAll }}
---
apiVersion: extensions/v1beta1
kind: DaemonSet
metadata:
name: {{ $daemonset }}
annotations:
{{ tuple $envAll | include "helm-toolkit.snippets.release_uuid" }}
spec:
{{ tuple $envAll $daemonset | include "helm-toolkit.snippets.kubernetes_upgrades_daemonset" | indent 2 }}
template:
metadata:
labels:
{{ list $envAll .Chart.Name $daemonset | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 8 }}
spec:
hostNetwork: true
hostPID: true
hostIPC: true
containers:
- name: {{ $daemonset }}
image: {{ .Values.images.divingbell }}
imagePullPolicy: {{ .Values.images.pull_policy }}
{{ tuple $envAll $envAll.Values.pod.resources.perm | include "helm-toolkit.snippets.kubernetes_resources" | indent 8 }}
command:
- /tmp/{{ $daemonset }}.sh
volumeMounts:
- name: rootfs-{{ $daemonset }}
mountPath: {{ .Values.conf.chroot_mnt_path }}
- name: {{ $secretName }}
mountPath: /tmp/{{ $daemonset }}.sh
subPath: {{ $daemonset }}
readOnly: true
securityContext:
privileged: true
volumes:
- name: rootfs-{{ $daemonset }}
hostPath:
path: /
- name: {{ $secretName }}
secret:
secretName: {{ $secretName }}
defaultMode: 0555
{{- end }}
{{- end }}
{{- if .Values.manifests.daemonset_perm }}
{{- $daemonset := "perm" }}
{{- $secretName := "divingbell-perm" }}
{{- $daemonset_yaml := list $daemonset $secretName . | include "divingbell.daemonset.perm" | toString | fromYaml }}
{{- $secret_include := "divingbell.secret.perm" }}
{{- list $daemonset $daemonset_yaml $secret_include $secretName . | include "helm-toolkit.utils.daemonset_overrides" }}
{{- end }}

View File

@ -0,0 +1,29 @@
{{/*
Copyright 2018 The Openstack-Helm Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/}}
{{- define "divingbell.secret.perm" }}
{{- $secretName := index . 0 }}
{{- $envAll := index . 1 }}
{{- with $envAll }}
---
apiVersion: v1
kind: Secret
metadata:
name: {{ $secretName }}
data:
perm: {{ tuple "bin/_perm.sh.tpl" . | include "helm-toolkit.utils.template" | b64enc }}
{{- end }}
{{- end }}

View File

@ -31,6 +31,47 @@ conf:
- telnetd-ssl
- nis
- ntpdate
# perm:
# -
# path: '/boot/System.map-*'
# owner: 'root'
# group: 'root'
# permissions: '0640'
# -
# path: '/etc/shadow'
# owner: 'root'
# group: 'shadow'
# permissions: '0640'
# -
# path: '/etc/gshadow'
# owner: 'root'
# group: 'shadow'
# permissions: '0640'
# -
# path: '/etc/passwd'
# owner: 'root'
# group: 'root'
# permissions: '0644'
# -
# path: '/etc/group'
# owner: 'root'
# group: 'root'
# permissions: '0644'
# -
# path: '/var/log/kern.log'
# owner: 'syslog'
# group: 'adm'
# permissions: '0640'
# -
# path: '/var/log/auth.log'
# owner: 'syslog'
# group: 'adm'
# permissions: '0640'
# -
# path: '/var/log/syslog'
# owner: 'syslog'
# group: 'adm'
# permissions: '0640'
## data.values.conf.sysctl
# sysctl:
@ -76,6 +117,10 @@ pod:
enabled: true
min_ready_seconds: 0
max_unavailable: 100%
perm:
enabled: true
min_ready_seconds: 0
max_unavailable: 100%
resources:
enabled: false
ethtool:
@ -113,6 +158,13 @@ pod:
requests:
memory: "128Mi"
cpu: "100m"
perm:
limits:
memory: "128Mi"
cpu: "100m"
requests:
memory: "128Mi"
cpu: "100m"
apt:
limits:
memory: "128Mi"
@ -128,3 +180,4 @@ manifests:
daemonset_sysctl: true
daemonset_limits: true
daemonset_apt: true
daemonset_perm: true

View File

@ -353,6 +353,88 @@ test_limits(){
echo "[SUCCESS] test range loop for limits passed successfully" >> "${TEST_RESULTS}"
}
_test_perm_value(){
local file=${1}
local owner=${2}
local group=${3}
local perm=${4}
local r_owner="$(stat -c %U ${file})"
local r_group="$(stat -c %G ${file})"
local r_perm="$(stat -c %a ${file})"
[ "${perm}"=="${r_perm}" ] && echo "+" || (echo "File ${file} permissions ${r_perm} but expected ${perm}"; exit 1)
[ "${owner}"=="${r_owner}" ] && echo "+" || (echo "File ${file} owner ${r_owner} but expected ${owner}"; exit 1)
[ "${group}"=="${r_group}" ] && echo "+" || (echo "File ${file} group ${r_group} but expected ${group}"; exit 1)
}
_perm_init_one(){
local file=${1}
local user=${file##*.}
useradd ${user} -U
chmod 777 ${file}
chown ${user}:${user} ${file}
echo ${file}
}
_make_p_temp(){
echo $(mktemp "${TMPDIR:-/tmp}/${0##*/}.XXXXXX")
}
_perm_init(){
# global vars!
p_test_file1=$(_perm_init_one $(_make_p_temp))
p_test_file2=$(_perm_init_one $(_make_p_temp))
}
_perm_teardown_one(){
local file=${1}
local user=${file##*.}
deluser ${user} -q
rm -f ${file}
}
_perm_teardown(){
# global vars!
_perm_teardown_one ${p_test_file1}
unset p_test_file1
_perm_teardown_one ${p_test_file2}
unset p_test_file2
}
test_perm(){
_perm_init
local overrides_yaml=${LOGS_SUBDIR}/${FUNCNAME}.yaml
echo "conf:
perm:
-
path: ${p_test_file1}
owner: 'root'
group: 'shadow'
permissions: '0640'
-
path: ${p_test_file2}
owner: 'root'
group: 'shadow'
permissions: '0640'" > "${overrides_yaml}"
install_base "--values=${overrides_yaml}"
get_container_status perm
_test_perm_value ${p_test_file1} root shadow 640
_test_perm_value ${p_test_file2} root shadow 640
echo "[SUCCESS] Positive test for perm passed successfully" >> "${TEST_RESULTS}"
echo "conf:
perm:
-
path: ${p_test_file1}
owner: 'root'
group: 'shadow'
permissions: '0640'" > "${overrides_yaml}"
install_base "--values=${overrides_yaml}"
get_container_status perm
_test_perm_value ${p_test_file1} root shadow 640
_test_perm_value ${p_test_file2} ${p_test_file2##*.} ${p_test_file2##*.} 777
echo "[SUCCESS] Backup test for perm passed successfully" >> "${TEST_RESULTS}"
_perm_teardown
}
_test_if_mounted_positive(){
mountpoint "${1}" || (echo "Expect ${1} to be mounted, but was not"; exit 1)
df -h | grep "${1}" | grep "${2}" ||
@ -971,9 +1053,9 @@ test_overrides(){
# Compare against expected number of generated daemonsets
daemonset_count="$(echo "${tc_output}" | grep 'kind: DaemonSet' | wc -l)"
if [ "${daemonset_count}" != "14" ]; then
if [ "${daemonset_count}" != "15" ]; then
echo '[FAILURE] overrides test 1 failed' >> "${TEST_RESULTS}"
echo "Expected 14 daemonsets; got '${daemonset_count}'" >> "${TEST_RESULTS}"
echo "Expected 15 daemonsets; got '${daemonset_count}'" >> "${TEST_RESULTS}"
exit 1
else
echo '[SUCCESS] overrides test 1 passed successfully' >> "${TEST_RESULTS}"
@ -1153,6 +1235,7 @@ if [[ -z $SKIP_BASE_TESTS ]]; then
install_base
test_sysctl
test_limits
test_perm
test_mounts
test_ethtool
test_uamlite