跳板机用途只做ssh中转,为严格控制跳板机数据进出、命令管理等,特对跳板机入口操作进行限制管理。该脚本包含两种界面风格,详见下面说明 。
功能说明:
* 屏蔽用户对跳板机系统进行任何未授权操作操作
* 查询用户已授权主机,具备权限用户方可连接后台服务器
* 授权命令集合(密钥生成、上传、copy,密码更改等),可根据实际需求自定义
* 此脚本依赖于LDAP用户管理,如无LDAP服务,可自行定义用户和主机组对应关系即可
界面一:用户授权登陆主机数量不超过20台 * 通过选择左侧列表序号登陆右侧主机 * 选择可执行命令序号,进入执行命令界面,命令作用,后面说明
界面二:用户授权登陆主机数量超过20台 * 选择IP地址登陆序号,进入输入IP地址界面 * 选择可执行命令序号,进入执行命令界面,命令作用,后面说明
命令作用说明 * ssh-keygen : 生成本机ssh公钥 * ssh-copy-id : 将跳板机公钥复制到远程服务器上 * upload-local-key : 把本地公钥上传到跳板机上,实现跳板机免密连接 * passwd : 更改密码 * exit : 第一层为关闭当前会话,第二层为返回上一页 备注:除“upload-local-key”为自定义命令外,其它参考命令本身用法
完整代码
#!/bin/bash
# Version: v1.5
# Function: 用于跳板机入口控制
# Author: Sly Chen
# Create Date: Jun.13 2018
# 将脚本放在/etc/profile.d/目录下,并添加可执行权限
#set -x
# 导入系统函数
export LANG=en_US.UTF-8
. /etc/init.d/functions
SHELL_NAME=$(basename $BASH_SOURCE)
SHELL_NAME_PREFIX=$(echo $SHELL_NAME | sed 's/.sh$//')
SHELL_LOG="/tmp/${SHELL_NAME_PREFIX}.log"
# 以红色显示
red() {
echo -e "\033[31;40m$*\033[0m"
}
# 以绿色显示
green() {
echo -e "\033[32;40m$*\033[0m"
}
# Write Log
shell_log () {
LOG_INFO=$1
echo "$(date "+%Y-%m-%d") $(date "+%H:%M:%S") ${LOG_INFO}" >> ${SHELL_LOG}
}
login_banner (){
action "${LOGIN_USER} login success" /bin/true
cat << _EOF_
#######################################################################################
# Welcome Use Jumpserver To Login #
# Please contact the system administrator or Send mail to Sly@test.com #
#######################################################################################
_EOF_
}
get_hosts_info () {
LOGIN_USER=`whoami`
[[ "$LOGIN_USER" == "root" ]] && continue
# 屏蔽Ctrl+C
trap ':' INT
clear
# 定义不同用户连接跳板机展现不同旗标
login_banner
# 进入ldap api封装目录,用作用户登陆主机查询
# ldap api依赖于openldap-devel python-devel ; GET命令依赖于perl-libwww-perl
# yum -y install openldap-devel python-devel perl-libwww-perl
# Installing python-ldap: https://www.python-ldap.org/en/latest/installing.html#installing-from-source
cd /data/script/ldap
# 格式化主机名,并删除任意及禁止登陆主机权限
array_objects=($(python ldapadmin.py user hostinfo ${LOGIN_USER} | sed "s/\[\|,\|\]\|'//g; /*\|\!/d"))
# 定义命令数组
array_commands=(
"ssh-keygen --> authentication key generation, management and conversion"
"ssh-copy-id --> use locally available keys to authorise logins on a remote machine"
"upload-local-key --> upload the public key to the jumpserver"
"passwd --> update user's authentication tokens"
"exit --> return"
)
CMD_LIST_NAME="$(green "Execute Command") On Jumpserver."
CLOSE_BASH="$(green "Exit Shell")"
if [ -z "${#array_objects[@]}" ]; then
red "No action object was found!"
continue
# 如果可登陆主机数超过20条,则通过自行指定IP地址登陆
elif [ ${#array_objects[@]} -gt 20 ]; then
IP_CUSTOM_NAME="Type $(green 'IP ADDRESS') To Login."
array_objects=("${IP_CUSTOM_NAME}" "${CMD_LIST_NAME}")
else
num_host=${#array_objects[@]}
array_objects[((num_host+1))]="${CMD_LIST_NAME}"
fi
}
network_pint_test () {
ping -c2 $LAN_IP &> /dev/null
[ $? -ne 0 ] && echo "$(red "$LAN_IP"): Network is unreachable" && continue
ssh ${LAN_IP}
}
invalid_ldap_host_del () {
# 本函数用作LDAP无效主机条目删除
# 如果获取内网IP为空,先判断运维平台API网络状态
ping -c 2 ${BRIDGE_URL} &> /dev/null
[ $? -ne 0 ] && echo "$(red "$BRIDGE_URL"): Network is unreachable" && continue
# 删除LDAP无效主机记录
LDAP_HOST_DEL=$(python ldapadmin.py user hostdel ${LOGIN_USER} ${OBJECT} | egrep -io 'sucessfully' | tr 'A-Z' 'a-z')
# 记录删除主机日志
if [ "${LDAP_HOST_DEL}" == "sucessfully" ]; then
shell_log "${LOGIN_USER} LDAP delete $(green "$OBJECT") sucessfully"
else
shell_log "${LOGIN_USER} LDAP delete $(red "$OBJECT") failure "
fi
}
main () {
get_hosts_info
# 获取IP数组生成菜单列表
PS3=$(green "\nAccept Only List Numbers: ")
# 必须加while死循环,不然无法屏蔽ctrl+d等操作
BRIDGE_URL='bridge.test.com'
while true; do
select VAR in "${array_objects[@]}" "${CLOSE_BASH}"; do
[ -z "$VAR" ] && red "Invalid number" && continue
if [[ "$VAR" == ${IP_CUSTOM_NAME} ]]; then
read -p "Type $(green 'IP ADDRESS') To Login: " LAN_IP
network_pint_test
elif [[ "$VAR" == "${CLOSE_BASH}" ]]; then
exit
elif [ "$VAR" != "${CMD_LIST_NAME}" ]; then
# 判断操作对象,IP加执行SSH前缀执行,命令直接执行
OBJECT=$(echo "${array_objects[@]}" | egrep -wo "${VAR}" | awk '{print $1}')
# 操作对象包含数字,选择序号对应命令就等于 ssh + ip
if [[ "$OBJECT" =~ .test.com ]]; then
[ x"$(which GET &> /dev/null; echo $?)" != x"0" ] &&
{
# GET依赖于perl-libwww-perl包
echo "-bash: $(red "GET"): command not found"
exit
}
LAN_IP=$(GET http://${BRIDGE_URL}/api/vm?hostname=${OBJECT} | grep -oP '"lan_ip[" :]+\K[^"]+')
# IP为空表示主机不存在,LDAP主机条目无效
if [ -z "$LAN_IP" ]; then
LAN_IP=$(GET http://${BRIDGE_URL}/api/phyhost?hostname=${OBJECT} | grep -oP '"lan_ip[" :]+\K[^"]+')
if [ -z "$LAN_IP" ]; then
# LDAP无效主机条目权限删除
invalid_ldap_host_del
echo "$(red "$OBJECT") not found"
continue
elif [ $(echo $LAN_IP | xargs -n 1 | wc -l) -gt 1 ]; then
echo "$(red "${OBJECT}") Contains multiple IP: $(echo ${LAN_IP} | xargs -n 10)"
continue
else
network_pint_test
fi
# 存在多个内网IP则退出执行
elif [ $(echo $LAN_IP | xargs -n 1 | wc -l) -gt 1 ]; then
echo "$(red "${OBJECT}") Contains multiple IP: $(echo ${LAN_IP} | xargs -n 10)"
continue
fi
network_pint_test
else
echo "$(red "$VAR") Hostname does not meet the standard"
continue
fi
# 判断变量为命令集合,则进入命令操作界面
elif [[ "$VAR" == "${CMD_LIST_NAME}" ]]; then
select COMMADN_SRC in "${array_commands[@]}"; do
[ -z "${COMMADN_SRC}" ] && red "Invalid command" && continue
COMMAND=$(echo "${COMMADN_SRC}" | awk '{print $1}')
if [ "$COMMAND" == "ssh-keygen" -o "$COMMAND" == "passwd" ]; then
# 执行命令
${COMMAND}
elif [[ "$COMMAND" == "ssh-copy-id" ]]; then
read -p "Please specify the IP: " IP
# 判断指定IP合法、网络通信
# 执行ssh-copy-id $IP
ssh-copy-id $IP
elif [[ "$COMMAND" == "exit" ]]; then
break
elif [[ "$COMMAND" == "upload-local-key" ]]; then
read -p "$(green "Please enter the public key content:") " KEY
if [ -z "$KEY" ]; then
echo "The KEY is empty."
elif [ -f "/home/${LOGIN_USER}/.ssh/authorized_keys" ]; then
[ -n "$(grep "$KEY" /home/${LOGIN_USER}/.ssh/authorized_keys)" ] &&
{
echo "The KEY already exists."
continue
}
fi
echo "$KEY" >> /home/${LOGIN_USER}/.ssh/authorized_keys
echo -e "\nUpload to complete."
fi
done
fi
done
done
}
main