Merge "Add ability to set user password in uamlite"
This commit is contained in:
commit
fcd97ef51c
@ -152,9 +152,9 @@ WantedBy=multi-user.target"
|
||||
|
||||
{{- range $iface, $unused := .Values.conf.ethtool }}
|
||||
{{- range $ethtool_key, $ethtool_val := . }}
|
||||
device={{ $iface | quote }} \
|
||||
user_key={{ $ethtool_key | quote }} \
|
||||
user_val={{ $ethtool_val | quote }} \
|
||||
device={{ $iface | squote }} \
|
||||
user_key={{ $ethtool_key | squote }} \
|
||||
user_val={{ $ethtool_val | squote }} \
|
||||
add_ethtool_param
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
@ -107,7 +107,7 @@ WantedBy=local-fs.target"
|
||||
|
||||
{{- range .Values.conf.mounts }}
|
||||
{{- range $key, $value := . }}
|
||||
{{ $key }}={{ $value | quote }} \
|
||||
{{ $key }}={{ $value | squote }} \
|
||||
{{- end }}
|
||||
add_mounts_param
|
||||
{{- end }}
|
||||
|
@ -90,7 +90,7 @@ add_sysctl_param(){
|
||||
}
|
||||
|
||||
{{- range $key, $value := .Values.conf.sysctl }}
|
||||
add_sysctl_param {{ $key | quote }} {{ $value | quote }}
|
||||
add_sysctl_param {{ $key | squote }} {{ $value | squote }}
|
||||
{{- end }}
|
||||
|
||||
# Revert any previously applied sysctl settings which are now absent
|
||||
|
@ -27,6 +27,7 @@ builtin_acct='ubuntu'
|
||||
add_user(){
|
||||
die_if_null "${user_name}" ", 'user_name' env var not initialized"
|
||||
: ${user_sudo:=false}
|
||||
: ${user_crypt_passwd:=*}
|
||||
|
||||
# Create user if user does not already exist
|
||||
getent passwd ${user_name} && \
|
||||
@ -41,10 +42,31 @@ add_user(){
|
||||
log.INFO "User '${user_name}' has been unexpired"
|
||||
fi
|
||||
|
||||
# Exclude case where user should not have a password set
|
||||
if [ "${user_crypt_passwd}" != '*' ]; then
|
||||
local user_has_passwd=true
|
||||
fi
|
||||
# Set user password if current password does not match desired password
|
||||
local crypt_passwd="$(getent shadow ${user_name} | cut -d':' -f2)"
|
||||
if [ "${crypt_passwd}" != "${user_crypt_passwd}" ]; then
|
||||
usermod -p "${user_crypt_passwd}" ${user_name}
|
||||
if [ "${user_has_passwd}" = 'true' ]; then
|
||||
log.INFO "User '${user_name}' password set successfully"
|
||||
else
|
||||
log.INFO "User '${user_name}' password removed successfully"
|
||||
fi
|
||||
else
|
||||
if [ "${user_has_passwd}" = 'true' ]; then
|
||||
log.INFO "No change required to password for user '${user_name}'"
|
||||
else
|
||||
log.INFO "User '${user_name}' has no password, and none was requested"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Add sudoers entry if requested for user
|
||||
if [ "${user_sudo}" = 'true' ]; then
|
||||
# Add sudoers entry if it does not already exist
|
||||
user_sudo_file=/etc/sudoers.d/${keyword}-${user_name}-sudo
|
||||
local user_sudo_file=/etc/sudoers.d/${keyword}-${user_name}-sudo
|
||||
if [ -f "${user_sudo_file}" ] ; then
|
||||
log.INFO "User '${user_name}' already added to sudoers: ${user_sudo_file}"
|
||||
else
|
||||
@ -56,15 +78,21 @@ add_user(){
|
||||
log.INFO "User '${user_name}' was not requested sudo access"
|
||||
fi
|
||||
|
||||
if [ "${user_has_passwd}" = "true" ] && \
|
||||
[ "${user_sudo}" = "true" ] && \
|
||||
[ "${user_name}" != "${builtin_acct}" ]; then
|
||||
expire_builtin_acct_passwd_vote=true
|
||||
fi
|
||||
|
||||
curr_userlist="${curr_userlist}${user_name}"$'\n'
|
||||
}
|
||||
|
||||
add_sshkeys(){
|
||||
die_if_null "${user_name}" ", 'user_name' env var not initialized"
|
||||
user_sshkeys="$@"
|
||||
local user_sshkeys="$@"
|
||||
|
||||
sshkey_dir="/home/${user_name}/.ssh"
|
||||
sshkey_file="${sshkey_dir}/authorized_keys"
|
||||
local sshkey_dir="/home/${user_name}/.ssh"
|
||||
local sshkey_file="${sshkey_dir}/authorized_keys"
|
||||
if [ -z "${user_sshkeys}" ]; then
|
||||
log.INFO "User '${user_name}' has no SSH keys defined"
|
||||
if [ -f "${sshkey_file}" ]; then
|
||||
@ -72,11 +100,11 @@ add_sshkeys(){
|
||||
log.INFO "User '${user_name}' has had its authorized_keys file wiped"
|
||||
fi
|
||||
else
|
||||
sshkey_file_contents='# NOTE: This file is managed by divingbell'$'\n'
|
||||
local sshkey_file_contents='# NOTE: This file is managed by divingbell'$'\n'
|
||||
for sshkey in "$@"; do
|
||||
sshkey_file_contents="${sshkey_file_contents}${sshkey}"$'\n'
|
||||
done
|
||||
write_file=false
|
||||
local write_file=false
|
||||
if [ -f "${sshkey_file}" ]; then
|
||||
if [ "$(cat "${sshkey_file}")" = \
|
||||
"$(echo "${sshkey_file_contents}" | head -n-1)" ]; then
|
||||
@ -98,33 +126,44 @@ add_sshkeys(){
|
||||
|
||||
# In the event that the user specifies ssh keys for the built-in account and
|
||||
# no others, do not expire the built-in account
|
||||
if [ "${user_name}" != "${builtin_acct}" ]; then
|
||||
expire_builtin_acct=true
|
||||
if [ "${user_sudo}" = "true" ] && \
|
||||
[ "${user_name}" != "${builtin_acct}" ]; then
|
||||
expire_builtin_acct_ssh_vote=true
|
||||
fi
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
{{- if hasKey .Values.conf "uamlite" }}
|
||||
{{- if hasKey .Values.conf.uamlite "purge_expired_users" }}
|
||||
purge_expired_users={{ .Values.conf.uamlite.purge_expired_users | quote }}
|
||||
purge_expired_users={{ .Values.conf.uamlite.purge_expired_users | squote }}
|
||||
{{- end }}
|
||||
{{- if hasKey .Values.conf.uamlite "users" }}
|
||||
{{- range $item := .Values.conf.uamlite.users }}
|
||||
{{- range $key, $value := . }}
|
||||
{{ $key }}={{ $value | quote }} \
|
||||
{{- if eq $key "user_crypt_passwd" }}
|
||||
{{/* supported crypt types are 2a (blowfish), 1 (md5), 5 (sha-256), and 6 (sha-512) */}}
|
||||
{{- if not (or (regexMatch "\\$2a\\$.*\\$.*" $value) (regexMatch "\\$[156]\\$.*\\$.*" $value)) }}
|
||||
{{- fail (print "BAD PASSWORD FOR '" $item.user_name "': The 'user_crypt_passwd' specified for '" $item.user_name "' does not pass regex checks. Ensure that the supplied user password is encoded per divingbell documentation at https://divingbell.readthedocs.io/en/latest/#uamlite") }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{ $key }}={{ $value | squote }} \
|
||||
{{- end }}
|
||||
add_user
|
||||
|
||||
{{- range $key, $value := . }}
|
||||
{{ $key }}={{ $value | quote }} \
|
||||
{{ $key }}={{ $value | squote }} \
|
||||
{{- end }}
|
||||
add_sshkeys {{ range $ssh_key := .user_sshkeys }}{{ $ssh_key | quote }} {{end}}
|
||||
{{- if hasKey . "user_sshkeys" }}
|
||||
{{- if not (eq (first .user_sshkeys) "Unmanaged") }}
|
||||
add_sshkeys {{ range $ssh_key := .user_sshkeys }}{{ if not (or (regexMatch "ssh-dss .*" $ssh_key) (regexMatch "ecdsa-.*" $ssh_key) (regexMatch "ssh-ed25519 .*" $ssh_key) (regexMatch "ssh-rsa .*" $ssh_key)) }}{{ fail (print "BAD SSH KEY FOR '" $item.user_name "': One of the 'user_sshkeys' specified for '" $item.user_name "' does not pass regex checks: '" $ssh_key "'. Ensure that the supplied user SSH keys are supported/formatted per divingbell documentation at https://divingbell.readthedocs.io/en/latest/#uamlite") }}{{ else }}{{ $ssh_key | squote }}{{ end }} {{ end }}
|
||||
{{- end }}
|
||||
{{- else }}
|
||||
add_sshkeys
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
# TODO: This should be done before applying new settings rather than after
|
||||
# Expire any previously defined users that are no longer defined
|
||||
if [ -n "$(getent passwd | grep ${keyword} | cut -d':' -f1)" ]; then
|
||||
users="$(getent passwd | grep ${keyword} | cut -d':' -f1)"
|
||||
@ -163,7 +202,8 @@ fi
|
||||
if [ -n "${builtin_acct}" ] && [ -n "$(getent passwd ${builtin_acct})" ]; then
|
||||
# Disable built-in account as long as there was at least one account defined
|
||||
# in this chart with a ssh key present
|
||||
if [ "${expire_builtin_acct}" = "true" ]; then
|
||||
if [ "${expire_builtin_acct_passwd_vote}" = "true" ] && \
|
||||
[ "${expire_builtin_acct_ssh_vote}" = "true" ]; then
|
||||
if [ "$(chage -l ${builtin_acct} | grep 'Account expires' | cut -d':' -f2 |
|
||||
tr -d '[:space:]')" = "never" ]; then
|
||||
usermod --expiredate 1 ${builtin_acct}
|
||||
|
@ -41,6 +41,7 @@ USERNAME2_SUDO=false
|
||||
USERNAME2_SSHKEY1="ssh-rsa xyz456 comment"
|
||||
USERNAME2_SSHKEY2="ssh-rsa qwe789 comment"
|
||||
USERNAME2_SSHKEY3="ssh-rsa rfv000 comment"
|
||||
USERNAME2_CRYPT_PASSWD='$6$AF.NLpphOJjMVTYC$GD6wyUTy9vIgatoMbtTDYcVtEJqh/Mrx3BRetVstMsNodSyn3ZFIZOMRePpRpGbFArnAxgkL1PtQxsZHCgtFn/'
|
||||
USERNAME3=userthree
|
||||
USERNAME3_SUDO=true
|
||||
USERNAME4=userfour
|
||||
@ -556,6 +557,16 @@ _test_ssh_keys(){
|
||||
fi
|
||||
}
|
||||
|
||||
_test_user_passwd(){
|
||||
username=$1
|
||||
crypt_passwd="$2"
|
||||
|
||||
if [ "$crypt_passwd" != "$(getent shadow $username | cut -d':' -f2)" ]; then
|
||||
echo "Error: User '$username' passwd did not match expected val '$crypt_passwd'"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
test_uamlite(){
|
||||
# Test the first set of values
|
||||
local overrides_yaml=${LOGS_SUBDIR}/${FUNCNAME}-set1.yaml
|
||||
@ -568,6 +579,7 @@ test_uamlite(){
|
||||
- ${USERNAME1_SSHKEY1}
|
||||
- user_name: ${USERNAME2}
|
||||
user_sudo: ${USERNAME2_SUDO}
|
||||
user_crypt_passwd: ${USERNAME2_CRYPT_PASSWD}
|
||||
user_sshkeys:
|
||||
- ${USERNAME2_SSHKEY1}
|
||||
- ${USERNAME2_SSHKEY2}
|
||||
@ -580,17 +592,21 @@ test_uamlite(){
|
||||
_test_user_enabled ${USERNAME1} true
|
||||
_test_sudo_enabled ${USERNAME1} ${USERNAME1_SUDO}
|
||||
_test_ssh_keys ${USERNAME1} "${USERNAME1_SSHKEY1}"
|
||||
_test_user_passwd ${USERNAME1} '*'
|
||||
_test_user_enabled ${USERNAME2} true
|
||||
_test_sudo_enabled ${USERNAME2} ${USERNAME2_SUDO}
|
||||
_test_ssh_keys ${USERNAME2} "${USERNAME2_SSHKEY1}"
|
||||
_test_ssh_keys ${USERNAME2} "${USERNAME2_SSHKEY2}"
|
||||
_test_ssh_keys ${USERNAME2} "${USERNAME2_SSHKEY3}"
|
||||
_test_user_passwd ${USERNAME2} ${USERNAME2_CRYPT_PASSWD}
|
||||
_test_user_enabled ${USERNAME3} true
|
||||
_test_sudo_enabled ${USERNAME3} ${USERNAME3_SUDO}
|
||||
_test_ssh_keys ${USERNAME3} false
|
||||
_test_user_passwd ${USERNAME3} '*'
|
||||
_test_user_enabled ${USERNAME4} true
|
||||
_test_sudo_enabled ${USERNAME4} ${USERNAME4_SUDO}
|
||||
_test_ssh_keys ${USERNAME4} false
|
||||
_test_user_passwd ${USERNAME4} '*'
|
||||
echo '[SUCCESS] uamlite test1 passed successfully' >> "${TEST_RESULTS}"
|
||||
|
||||
# Test an updated set of values
|
||||
@ -619,17 +635,21 @@ test_uamlite(){
|
||||
_test_user_enabled ${USERNAME1} true
|
||||
_test_sudo_enabled ${USERNAME1} ${uname1_sudo}
|
||||
_test_ssh_keys ${USERNAME1} false
|
||||
_test_user_passwd ${USERNAME1} '*'
|
||||
_test_user_enabled ${USERNAME2} true
|
||||
_test_sudo_enabled ${USERNAME2} ${uname2_sudo}
|
||||
_test_ssh_keys ${USERNAME2} "${USERNAME2_SSHKEY1}"
|
||||
_test_ssh_keys ${USERNAME2} "${USERNAME2_SSHKEY2}"
|
||||
_test_user_passwd ${USERNAME2} '*'
|
||||
_test_user_enabled ${USERNAME3} true
|
||||
_test_sudo_enabled ${USERNAME3} ${uname3_sudo}
|
||||
_test_ssh_keys ${USERNAME3} "${USERNAME1_SSHKEY1}"
|
||||
_test_ssh_keys ${USERNAME3} "${USERNAME2_SSHKEY3}"
|
||||
_test_user_passwd ${USERNAME3} '*'
|
||||
_test_user_enabled ${USERNAME4} true
|
||||
_test_sudo_enabled ${USERNAME4} ${USERNAME4_SUDO}
|
||||
_test_ssh_keys ${USERNAME4} false
|
||||
_test_user_passwd ${USERNAME4} '*'
|
||||
echo '[SUCCESS] uamlite test2 passed successfully' >> "${TEST_RESULTS}"
|
||||
|
||||
# Test revert/rollback functionality
|
||||
@ -646,7 +666,7 @@ test_uamlite(){
|
||||
echo '[SUCCESS] uamlite test3 passed successfully' >> "${TEST_RESULTS}"
|
||||
|
||||
# Test purge users flag
|
||||
overrides_yaml=${LOGS_SUBDIR}/${FUNCNAME}-set3.yaml
|
||||
overrides_yaml=${LOGS_SUBDIR}/${FUNCNAME}-set4.yaml
|
||||
echo "conf:
|
||||
uamlite:
|
||||
purge_expired_users: true" > "${overrides_yaml}"
|
||||
@ -657,6 +677,33 @@ test_uamlite(){
|
||||
_test_user_purged ${USERNAME3}
|
||||
_test_user_purged ${USERNAME4}
|
||||
echo '[SUCCESS] uamlite test4 passed successfully' >> "${TEST_RESULTS}"
|
||||
|
||||
# Test invalid password
|
||||
overrides_yaml=${LOGS_SUBDIR}/${FUNCNAME}-set5.yaml
|
||||
user2_crypt_passwd_invalid='plaintextPassword'
|
||||
echo "conf:
|
||||
uamlite:
|
||||
users:
|
||||
- user_name: ${USERNAME2}
|
||||
user_crypt_passwd: ${user2_crypt_passwd_invalid}" > "${overrides_yaml}"
|
||||
install_base "--values=${overrides_yaml}" 2>&1 | grep 'BAD PASSWORD' || \
|
||||
(echo "[FAIL] uamlite test5 did not receive expected 'BAD PASSWORD' error" && exit 1)
|
||||
echo '[SUCCESS] uamlite test5 passed successfully' >> "${TEST_RESULTS}"
|
||||
|
||||
# Test invalid SSH key
|
||||
overrides_yaml=${LOGS_SUBDIR}/${FUNCNAME}-set6.yaml
|
||||
user2_bad_sshkey='AAAAB3NzaC1yc2EAAAABIwAAAQEAklOUpkDHrfHY17SbrmT key-comment'
|
||||
echo "conf:
|
||||
uamlite:
|
||||
users:
|
||||
- user_name: ${USERNAME2}
|
||||
user_sshkeys:
|
||||
- ${USERNAME2_SSHKEY1}
|
||||
- ${user2_bad_sshkey}
|
||||
- ${USERNAME2_SSHKEY3}" > "${overrides_yaml}"
|
||||
install_base "--values=${overrides_yaml}" 2>&1 | grep 'BAD SSH KEY' || \
|
||||
(echo "[FAIL] uamlite test6 did not receive expected 'BAD SSH KEY' error" && exit 1)
|
||||
echo '[SUCCESS] uamlite test6 passed successfully' >> "${TEST_RESULTS}"
|
||||
}
|
||||
|
||||
# test daemonset value overrides for hosts and labels
|
||||
|
@ -17,9 +17,6 @@
|
||||
Divingbell
|
||||
==========
|
||||
|
||||
What is it?
|
||||
-----------
|
||||
|
||||
Divingbell is a lightweight solution for:
|
||||
1. Bare metal configuration management for a few very targeted use cases
|
||||
2. Bare metal package manager orchestration
|
||||
@ -66,10 +63,6 @@ fashion: the idempotent automation for each daemonset will only re-run when
|
||||
Armada spawns/respawns the container, or if information relevant to the host
|
||||
changes in the configmap.
|
||||
|
||||
For upgrades, a decision was taken not to use any of the built-in Kubernetes
|
||||
update strategies such as RollingUpdate. Instead, we are putting this on
|
||||
Armada to handle the orchestration of how to do upgrades (e.g., rack by rack).
|
||||
|
||||
Daemonset configs
|
||||
-----------------
|
||||
|
||||
@ -123,19 +116,73 @@ access. Ex::
|
||||
purge_expired_users: false
|
||||
users:
|
||||
- user_name: testuser
|
||||
user_sudo: True
|
||||
user_crypt_passwd: $6$...
|
||||
user_sudo: true
|
||||
user_sshkeys:
|
||||
- ssh-rsa AAAAB3N... key1-comment
|
||||
- ssh-rsa AAAAVY6... key2-comment
|
||||
|
||||
An update to the chart with revmoed users will result in those user's accounts
|
||||
being expired, preventing those users any access through those accounts. This
|
||||
does not delete their home directory or any other files, and provides UID
|
||||
consistency in the event the same account gets re-added later, and they regain
|
||||
access to their files again.
|
||||
Setting user passwords
|
||||
""""""""""""""""""""""
|
||||
|
||||
However, if it is desired to purge expired and removed accounts and their home
|
||||
directories, this may be done by the ``purge_expired_users`` option to ``true``.
|
||||
Including ``user_crypt_passwd`` to set a user password is optional.
|
||||
|
||||
If setting a password for the user, the chart expects the password to be
|
||||
encrypted with SHA-512 and formatted in the way that ``crypt`` library expects.
|
||||
Run the following command to generate the needed encrypted password from the
|
||||
plaintext password::
|
||||
|
||||
python3 -c "from getpass import getpass; from crypt import *; p=getpass(); print('\n'+crypt(p, METHOD_SHA512)) if p==getpass('Please repeat: ') else print('\nPassword mismatch.')"
|
||||
|
||||
Use the output of the above command as the ``user_crypt_passwd`` for the user.
|
||||
(Credit to `unix.stackexchange.com <https://unix.stackexchange.com/questions/81240/manually-generate-password-for-etc-shadow>`_.)
|
||||
If the password is not formatted how crypt expects, the chart will throw an
|
||||
error and fail to render.
|
||||
|
||||
At least one user must be defined with a password and sudo in order for the
|
||||
built-in ``ubuntu`` account to be disabled. This is because in a situation where
|
||||
network access is unavailable, console username/password access will be the only
|
||||
login option.
|
||||
|
||||
Setting user sudo
|
||||
"""""""""""""""""
|
||||
|
||||
Including ``user_sudo`` to set user sudo access is optional. The default value
|
||||
is ``false``.
|
||||
|
||||
At least one user must be defined with sudo access in order for the built-in
|
||||
``ubuntu`` account to be disabled.
|
||||
|
||||
SSH keys
|
||||
""""""""
|
||||
|
||||
Including ``user_sshkeys`` for defining one or more user SSH keys is optional.
|
||||
|
||||
The chart will throw an error and fail to render if the SSH key is not one of
|
||||
the following formats:
|
||||
|
||||
- dsa (ssh-dss ...)
|
||||
- ecdsa (ecdsa-...)
|
||||
- ed25519 (ssh-ed25519 ...)
|
||||
- rsa (ssh-rsa ...)
|
||||
|
||||
Setting ``user_sshkeys`` to ``[ Unmanaged ]`` will instruct divingbell not to
|
||||
manage the user's authorized_keys file.
|
||||
|
||||
At least one user must be defined with an SSH key and sudo in order for the
|
||||
built-in ``ubuntu`` account to be disabled.
|
||||
|
||||
Purging expired users
|
||||
"""""""""""""""""""""
|
||||
|
||||
Including the ``purge_expired_users`` key-value pair is optional. The default
|
||||
value is ``false``.
|
||||
|
||||
This option must be set to ``true`` if it is desired to purge expired accounts
|
||||
and remove their home directories. Otherwise, removed accounts are expired (so
|
||||
users cannot login) but their home directories remain intact, in order to
|
||||
maintain UID consistency (in the event the same accounts gets re-added later,
|
||||
they regain access to their home directory files without UID mismatching).
|
||||
|
||||
Node specific configurations
|
||||
----------------------------
|
||||
|
Loading…
x
Reference in New Issue
Block a user