企业集群架构-06-SSH

SSH

SSH基本概述

SSH是一个安全协议,在进行数据传输时,会对数据包进行加密处理,加密后在进行数据传输。确保了数据传输安全。

SSH服务主要功能:

  1. 提供远程连接服务器的服务
  2. 对传输的数据进行加密

SSHTelnet的区别:

  • ssh服务对传输数据进行加密,监听在本地22/tcp端口, ssh服务默认支持root用户登录
  • telnet服务不对数据进行加密,监听在本地23/tcp端口,,Telnet默认不支持root用户登录
服务连接方式 服务数据传输 服务监听端口 服务登陆用户
ssh 加密 22/tcp 默认支持root用户登陆
telnet 明文 23/tcp 不支持root用户登陆

企业面试题:

下列服务,分别使用的那个端口?

ftp     21/tcp
dns     53/udp
ssh     22/tcp
telnet  23/tcp
mysql   3306/tcp
http    80/tcp
https   443/tcp 443/udp

使用wireshark验证telnet明文传输与ssh加密传输

  1. 安装telnet服务并运行
[root@m01 ~]# yum -y install telnet-server
[root@m01 ~]# systemctl start telnet.socket
  1. 使用wireshark检测vmnet8网卡上telnet的流量

image-20200904151812698

  1. telnet无法使用root用户登录Linux系统,需要创建普通用户
[root@nfs ~]# useradd admin
[root@nfs ~]# echo "123"| passwd --stdin admin
  1. 使用普通用户进行telnet登录

image-20200904152427052

  1. 搜索wireshark包含telnet相关的流量

image-20200904152313367

image-20200904152652352

image-20200904152834628

  1. 使用wireshark分析ssh流量

img

img

img

img

SSH相关命令

SSH有客户端与服务端,我们将这种模式称为C/S架构,ssh客户端支持Windows、Linux、Mac等平台。
在ssh客户端中包含 ssh|slogin远程登陆、scp远程拷贝、sftp远程数据传输、ssh-copy-id秘钥分发等应用程序。


ssh远程登录服务器命令示例

ssh [-p port] [user@]hostname [command]
# -p指定连接远程主机端口,默认22端口可省略
# "@"前面为用户名,如果用当前用户连接,可以不指定用户
# "@"后面为要连接的服务器的IP
[root@m01 ~]# ssh -p22 root@10.0.0.41  # 远程登录服务器
[root@m01 ~]# ssh root@172.16.1.41 "hostname -i" # 远程在指定服务器执行命令
172.16.1.41

scp远程拷贝(全量复制)至远程主机命令示例

scp [-pr] [-P port] [-l limit] [[user@]host1:]file1 ... [[user@]host2:]file2
# -P 指定端口,默认22端口可不写
# -r 表示递归拷贝目录
# -p 表示在拷贝文件前后保持文件或目录属性不变
# -l 限制传输使用带宽(默认kb)
# 推:将本地/tmp/oldboy推送至远端服务器10.0.0.61的/tmp目录,使用对端的root用户
[root@m01 ~]# scp -P22 -rp /tmp/oldboy oldboy@10.0.0.61:/tmp
# 拉:将远程10.0.0.61服务器/tmp/oldboy文件拉取到本地/opt/目录下
[root@m01 ~]# scp -P22 -rp root@10.0.0.61:/tmp/oldboy /opt/
# 限速
[root@m01 ~]# scp /opt/1.txt root@172.16.1.31:/tmp
root@172.16.1.31 password: 
test                        100%  656MB  '83.9MB/s'   00:07 
# 限速为8096kb,换算为MB,要除以 8096/8=1024KB=1MB
[root@m01 ~]# scp -rp -l 8096  /opt/1.txt root@172.16.1.31:/tmp
root@172.16.1.31s password: 
test                        7%   48MB   '1.0MB/s'   09:45 

结论:

  1. scp通过ssh协议加密方式进行文件或目录拷贝。
  2. scp使用连接时指定的用户作为为拷贝文件或目录的权限。
  3. scp支持数据推送和拉取,每次都是全量拷贝,效率较低。

sftp远程数据传输命令

# 默认可以通过sftp命令连接sftp服务
sftp root@10.0.0.61
sftp -oPort=22222 root@10.0.0.61  # -o 使用ssh的选项

# sftp使用get下载文件至于本地服务器
sftp> get conf.txt /tmp/

# sftp使用put上传本地服务器文件至远程服务器
sftp> put /root/t1.txt /root/

SSH验证方式

基于账户密码远程登录

知道服务器的IP端口,账号密码,即可通过ssh客户端命令登陆远程主机。

➜  ~ ssh -p22 root@10.0.0.61
root@10.0.0.61 password:
[root@m01 ~]#

免交互方式一:sshpass

[root@m01 ~]# yum install -y sshpass
[option]
-p:指定密码
-f:从文件中取密码
-e:从环境变量中取密码
-P:设置密码提示

[root@m01 ~]# sshpass -p 123456 ssh root@10.0.0.51

免交互方式二:expect

[root@m01 ~]# yum install -y expect
#!/usr/bin/expect
set ip 10.0.0.31
set pass 123456
set timeout 30
spawn ssh root@$ip
expect {
        "(yes/no)" {send "yes\r"; exp_continue}
        "password:" {send "$pass\r"}
}
expect "root@"  {send "df -h\r"}
expect "root@"  {send "exit\r"}
expect eof

基于秘钥远程登录

默认情况下,通过ssh客户端命令登陆远程服务器,需要提供远程系统上的帐号与密码,但为了降低密码泄露的机率和提高登陆的方便性,建议使用密钥验证方式。

img

  1. 在服务器上生成非对称密钥,使用-t指定要创建的密钥类型, 使用-C提供新注释
[root@m01 ~]# ssh-keygen -t rsa -C 593528156@qq.com
...
# 默认一路回车即可
...
  1. 将A服务器上的公钥推送至B服务器
ssh-copy-id [-i [identity_file]] [user@]hostname

-i        # 指定下发的公钥文件的路径
[user@]   # 指定分发公钥的用户身份,默认以当前系统用户身份
hostname  # 下发公钥至那台服务器, 填写远程主机IP地址
# 分发公钥,[将A服务器的公钥写入B服务器的~/.ssh/authorized_keys文件中]
[root@m01 ~]# ssh-copy-id -i ~/.ssh/id_rsa.pub root@172.16.1.41
  1. 如果A服务器连接B服务器无需密码则表示秘钥已配置成功
[root@m01 ~]# ssh root@172.16.1.41
[root@nfs ~]#

注意:对端服务器用户家目录权限过高(777)也会导致无法连接

SSH应用场景

用户通过Windows/MAC/Linux客户端连接跳板机免密码登录,跳板机连接后端无外网的Linux主机实现免密登录,架构图如下。
实践多用户登陆一台服务器无密码
实践单用户登陆多台服务器免密码

img

  1. windows客户端使用Xshell生成秘钥对,并下发公钥至跳板机
  1. Xshell-->选择工具-->新建用户密钥生成向导
    image-20200904163404917

  2. 选择创建密钥类型和密钥长度,默认即可,选择下一步

image-20200904163501776

  1. 生成公钥对,选择下一步

image-20200904163556949

  1. 填写秘钥名称。秘钥加密密码不建议配置

image-20200904164700127

  1. Windows会提示密码为空,选是即可

image-20200904164748831

  1. 生成秘钥后,点击Xshell-->工具-->用户秘钥管理者

image-20200904164912044

  1. 选择对应秘钥的属性

image-20200904165142120

  1. 选择对应秘钥的公钥,将其复制或者保存为文件

image-20200904165514007

  1. 将从WIndows下复制好的公钥粘贴至跳板机~/.ssh/authorized_keys中,然后使用密钥连接方式测试
[root@m01 ~]# cd ; umask 077; mkdir -p .ssh ;cd .ssh
[root@m01 .ssh]# vim authorized_keys  # 添加windows公钥
  1. 跳板机下发公钥至后端主机
  1. 在跳板机上生成秘钥对
[root@m01 ~]# ssh-keygen -t rsa -C manager@qq.com
  1. 拷贝跳板机上的密钥至后端主机,如果SSH不是使用默认22端口, 使用-p指定对应端口
[root@m01 ~]# ssh-copy-id  -i /root/.ssh/id_rsa.pub "-p22 root@172.16.1.31"
[root@m01 ~]# ssh-copy-id  -i /root/.ssh/id_rsa.pub "-p22 root@172.16.1.41"
  1. 在m01管理机上测试是否成功登陆两台服务器
[root@m01 ~]# ssh root@172.16.1.41
[root@nfs01 ~]# exit

[root@m01 ~]# ssh root@1172.16.1.31
[root@backup ~]# exit
  1. 通过跳板机能实现scp拷贝文件免密码
[root@m01 ~]# scp zls.txt root@172.16.1.31:/tmp
zls.txt                 100%    0     0.0KB/s   00:00    
[root@m01 ~]# scp zls.txt root@172.16.1.41:/tmp
zls.txt                 100%    0     0.0KB/s   00:00  
  1. 通过跳板机获取所有机器的load,CPU,Memory等信息(思考:如果服务器数量多,如何并发查看和分发数据)
[root@m01 ~]# cat all.sh 
#!/usr/bin/bash
[ $# -ne 1 ] && echo "请输入执行的命令" && exit 1

for i in 31 41
do
	echo "#########172.16.1.$i#####"
	ssh root@172.16.1.$i "$1"
done
  1. 脚本实现(跳板机)
#!/usr/bin/env bash
# jumpserver
# 局部变量:主机IP
lb01=10.0.0.5
lb02=10.0.0.6
web01=10.0.0.7
web02=10.0.0.8
web03=10.0.0.9
nfs=10.0.0.31
backup=10.0.0.41
db01=10.0.0.51
m01=10.0.0.61
zabbix=10.0.0.71

# 身份判断函数 []<-(msg:String)
judge(){
echo "1. 运维"
echo "2. 开发"
read -p "请输入你是?[运维1|开发2] " post
case $post in
    1)
	  read -sp "欢迎最牛逼的运维人员,请输入你的密码信息:" passwd
      [[ $passwd != "woshiyunwei" ]] && echo "你这个糟老头子坏的很,拜拜!!" && exit
	  ;;
	2)
	  echo "未开发"
      exit
	  ;;
esac
}

judge

# 菜单函数 []<-()
menu(){
		cat <<-EOF
		+--------------------------+
		|     1)  lb01             |
		|     2)  lb02             |
		|     3)  web01            |
		|     4)  web02            |
		|     5)  web03            |
		|     6)  nfs              |
		|     7)  backup           |
		|     8)  db01             |
		|     9)  m01              |
		|     10) zabbix           |
		|     h)  help             |
		+--------------------------+
EOF
}

menu

# 连接函数 []<-(msg:String)
connect(){
  ping -c 1 -w 1 $1 &>/dev/null
  if [ $? -eq 0 ];then
    ssh root@$1
  else
    echo -e "\033[5;4;40;31m 别连了,我的哥,$2:$1机器都没开!!!\033[0m"
  fi
}

# 控制不让输入ctrl+c,ctrl+z
trap "" HUP INT TSTP

# 选择分支保持监听
while true
do
	read -p "请输入要连接的主机编号:" num
	case $num in
			1|lb01)
              connect $lb01 lb01
					;;
			2|lb02)
              connect $lb02 lb02
					;;
			3|web01)
              connect $web01 web01
					;;
			4|web02)
              connect $web02 web02
					;;
			5|web03)
			  connect $web03 web03
					;;
			6|nfs)
              connect $nfs nfs
					;;
			7|backup)
			  connect $backup backup
					;;
			8|db01)
			  connect $db01 db01
					;;
			9|m01)
			  connect $m01 m01
					;;
			10|zabbix)
			  connect $zabbix zabbix
					;;
			h|help)
			  clear
			  menu
					;;
			close)
			  break
					;;
	esac
done
  1. 脚本实现(图形化跳板机)
#!/bin/bash

lb01=10.0.0.5
lb02=10.0.0.6
web01=10.0.0.7
web02=10.0.0.8
web03=10.0.0.9
nfs=10.0.0.31
backup=10.0.0.41
db01=10.0.0.51
db02=10.0.0.52
m01=10.0.0.61
zabbix=10.0.0.71

title="欢迎进入lnb跳板机-$m01"

# 跳板机函数
JUMP(){
             OPTION=$(whiptail --title "$title"  --menu "请选择你要连接的服务器:" 25 60 11 \
              "1" "连接 lb01" \
              "2" "连接 lb02" \
              "3" "连接 web01" \
              "4" "连接 web02" \
              "5" "连接 web03" \
              "6" "连接 nfs" \
              "7" "连接 backup" \
              "8" "连接 db01" \
              "9" "连接 db02" \
              "10" "连接 m01" \
              "11" "连接 zabbix"  3>&1 1>&2 2>&3)

		 exitstatus=$?
		 if [ $exitstatus = 0 ]; then
			case $OPTION in
            		    1)
            		    connect $lb01
            		    ;;
            		    2)
            		    connect $lb02
            		    ;;
            		    3)
            		    connect $web01
            		    ;;
            		    4)
            		    connect $web02
            		    ;;
            		    5)
            		    connect $web03
            		    ;;
            		    6)
            		    connect $nfs
            		    ;;
            		    7)
            		    connect $backup
            		    ;;
            		    8)
            		    connect $db01
            		    ;;
            		    9)
            		    connect $db02
            		    ;;
            		    10)
            		    connect $m01
            		    ;;
            		    11)
            		    connect $zabbix
            		    ;;
            		    12)
            		    connect $te
            		    ;;
            		    13)
            		    connect $te_web
            		    ;;
            		    esac
 		fi
}

# 主机函数
HOST_INFO (){
	        HOST=$(whiptail --title "$title" --checklist \
                "请选择要发送的主机名:" 25 60 11 \
                "$lb01" "发送给lb01" OFF \
                "$lb02" "发送给lb01" OFF \
                "$web01" "发送给web01" OFF \
                "$web02" "发送给web02" OFF \
                "$web03" "发送给web03" OFF \
                "$nfs" "发送给nfs" OFF \
                "$backup" "发送给backup" OFF \
                "$db01" "发送给db01" OFF \
                "$db02" "发送给db02" OFF \
                "$m01" "发送给m01" OFF \
                "$zabbix" "发送给zabbix" OFF 3>&1 1>&2 2>&3)
}

SER_INFO(){
                SER=$(whiptail --title "$title" --checklist \
                "请选择要检查的服务:" 25 60 10 \
                "nginx" "检查nginx" OFF \
                "mysqld" "检查mysqld" OFF \
                "php" "检查php" OFF \
                "tomcat" "检查tomcat" OFF \
                "sshd" "检查sshd" OFF \
                "httpd" "检查httpd" OFF \
                "vsftpd" "检查vsftpd" OFF \
                "docker" "检查docker" OFF \
                "saltstack" "检查saltstack" OFF \
                "rsyncd" "检查rsyncd" OFF 3>&1 1>&2 2>&3)
}

# 连接函数
connect(){
  whiptail --title "$title" --yesno "你确定要连接这台机器么?想好了啊!!!" 10 60
  if [ $? -eq 0 ];then
            {
            ping -c 1 -w 1 $1 >/tmp/ping.txt 2>/dev/null
            if [ $? -ne 0 ];then
                for ((i = 0 ; i <= 100 ; i+=30)); do
                        sleep 1
                        echo $i
                done
            fi
            } | whiptail --gauge "emmmm...我正在连接$1,检测网络中,等我一哈子..." 6 60 0
            grep 'ttl' /tmp/ping.txt &>/dev/null
            if [ $? -eq 0 ];then
                ssh root@$1
            else
                whiptail --title "$title" --msgbox "网络检测失败,别连了,我的哥,$1机器都没开" 10 60
            fi

  fi
}

# 推送文件函数
SCP (){
		HOST_INFO

                PA=$(whiptail --title "$title" --inputbox "请输入需要推送的文件本地路径:" 10 60 /etc/passwd 3>&1 1>&2 2>&3)
                DEST=$(whiptail --title "$title" --inputbox "请输入需要分发到主机的哪个目录:" 10 60 /tmp 3>&1 1>&2 2>&3)
                {
                for H in ${HOST};do
                        echo "scp $PA ${H}:${DEST}"|bash &>/dev/null
                        for ((i = 0 ; i <= 100 ; i+=50));do
                                sleep 1
                                echo $i
                        done
                done
                } | whiptail --gauge "别着急,正在传送中..." 6 60 0
}

# 检查磁盘函数
CHECK_DISK (){
		HOST_INFO

                for H in ${HOST};do
			echo "ssh $H 'df -h' "|bash > /tmp/disk
			whiptail --title "$(date +%F-%T) | $H 磁盘信息" --msgbox "$(cat /tmp/disk)" 10 60
                done
}

# 检查内存函数
CHECK_MEM (){
                HOST_INFO

                for H in ${HOST};do
                        echo "ssh $H 'free -m' "|bash > /tmp/meminfo
                        whiptail --title "$(date +%F-%T) | $H 内存信息" --msgbox "$(cat /tmp/meminfo)" 30 80
                done
}

# 查看服务状态
CHECK_SER (){
		HOST_INFO
		SER_INFO

		for H in ${HOST};do
			for S in ${SER};do
				HO=`echo "$H"|awk -F \" '{print $2}'`
				PROC=`ssh $HO "ps -ef|grep $S|wc -l"`
				NUM=$( expr $PROC - 3 )
				if [[ $PROC > 3 ]];then
					whiptail --title "$(date +%F-%T) | $H 服务信息" --msgbox "${S} 存活 | 进程数:$NUM" 10 60
				else
					whiptail --title "$(date +%F-%T) | $H 服务信息" --msgbox "${S} 没有存活| 进程数:$NUM" 10 60
				fi
			done
		done
}

# 批量之心命令函数
EXEC_CMD(){
		HOST_INFO
		CMD=$(whiptail --title "$title" --inputbox "请输入要执行的命令:" 10 60 ifconfig 3>&1 1>&2 2>&3)
        for H in ${HOST};do
			HO=`echo "$H"|awk -F \" '{print $2}'`
			RES=`ssh $HO "$CMD"`
			whiptail --title "$(date +%F-%T) | $H 命令执行结果" --msgbox "$RES" 40 80
		done
}

# 退出函数
EXIT(){
                pass=$(whiptail --title "$title" --passwordbox "请输入你的退出密码" 10 60 3>&1 1>&2 2>&3)
                if [ $pass == '123456' ];then
                        exit
                else
                        whiptail --title "$title" --msgbox "密码错误,你不是运维,小样的~~~" 10 60
                        continue
                fi
}

whiptail --title "$title" --msgbox "lnb跳板机,给你全新不一样的feel,进去了,就不想出来" 10 60

# 控制不让输入ctrl+c,ctrl+z
trap "" HUP INT TSTP

# 选择分支保持监听
while true;do
	OPTION=$(whiptail --title "$title" --menu "请选择你的动作(轻点...)" 15 60 8 \
	"1" "SSH远程连接" \
	"2" "推送文件" \
	"3" "查看磁盘空间" \
	"4" "查看内存空间" \
	"5" "查看服务状态" \
	"6" "批量执行命令" \
	"7" "轻松一下(game)" \
	"8" "退出"  3>&1 1>&2 2>&3)

	exitstatus=$?
	if [ $exitstatus = 0 ]; then
	    case $OPTION in
		1)
		JUMP
		;;
		2)
		SCP
		;;
		3)
		CHECK_DISK
		;;
		4)
		CHECK_MEM
		;;
		5)
		CHECK_SER
		;;
		6)
		EXEC_CMD
		;;
		7)
		sh /root/eluosi.sh
		;;
		8)
		EXIT
		;;
		esac
	fi
done

SSH安全优化

SSH作为远程连接服务,通常我们需要考虑到该服务的安全,所以需要对该服务进行安全方面的配置。

  1. 变更远程连接登陆的端口
  2. 禁止ROOT管理员直接登录
  3. 密码认证方式改为密钥认证
  4. 重要服务不使用公网IP地址
  5. 使用防火墙限制来源IP地址

SSH服务参数:

Port 6666                    # 变更SSH服务远程连接端口
PermitRootLogin         no   # 禁止root用户直接远程登录
PasswordAuthentication  no   # 禁止使用密码直接远程登录
UseDNS                  no   # 禁止ssh进行dns反向解析,打开影响ssh连接效率
GSSAPIAuthentication    no   # 禁止GSS认证,禁止减少连接时产生的延迟

将如下具体配置添加至/etc/ssh/sshd_config文件中,参数需根据实际情况进行调整

[root@m01 ~]# cat >>/etc/ssh/sshd_config <<-EOF
>#Port 6666
>#PasswordAuthentication no
>#PermitRootLogin no
>UseDNS no
>GSSAPIAuthentication no
>EOF
posted @ 2021-03-03 21:02  原因与结果  阅读(176)  评论(0编辑  收藏  举报