背景

部门切换到jumpserver来管理服务器,并且打开了MFA两步验证这个强制选项,意味着登入的时候需要登入密码,之后还有登入MFA验证码,这样导致我在登入服务器的时候非常麻烦,

更新一下

Untitled

并且我是通过vscode远程开发+手机热点远程办公,经常手机掉线就要重连,非常麻烦。

解决过程

MFA验证码我已经通过 oathtool --totp --base32 工具加秘钥计算出来,之前一直是通过别名的方式计算该值然后填充到命令行,但是一天要输入好几十次。

今天试了一下通过expect 来解决这个问题,主要目标是写一个expect脚本参数就是ssh 正常登入的参数,expect 捕获参数自动填充验证码。

具体代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#!/usr/bin/expect

# 获取所有参数
set args [join $argv " "]

# 构建SSH命令字符串
set ssh_command "/usr/bin/ssh"
# 打印SSH命令
puts "SSH Command: $ssh_command"

set command "oathtool --totp --base32 '*****'"
set fa [exec sh -c $command]

spawn $ssh_command $args

expect {
"OTP Code" {
send "$fa\r"
interact
}
"Last login:" {
interact
}
}

exit

执行这行代码的时候spawn $ssh_command $args 如果填写一个参数就没问题,

如脚本的名称是ssh.exp 那么执行 ssh.exp ip1 or ssh.exp -V 都是没问题的,但是多加几个参数如 ssh.exp -v -V -s 就会报expect: illegal option -- V

看了下man spawn 是这样调用的spawn [args] program [args] 应该是在执行的时候把-v -V -s 当成一整个参数传递进去了。

查找了往上相关的资料和文档,都没有找到对应的答案,后来通过gpt找到了通过参数扩展的语法可以实现参数的扩展。

最终的语法是:spawn $ssh_command {*}$args

这段是gpt的解释:

{*} 是在Tcl语言中的一个特殊语法,用于展开一个列表并将其元素作为多个参数传递给一个命令。

在Expect脚本中,Tcl是一种解释性语言,而Expect是Tcl的扩展,因此它继承了Tcl的特性。**{*}** 用于将列表的元素展开,以便能够正确传递给接受多个参数的命令。

gpt真的好用。

总结

最终是实现了脚本自动登入的过程,然而参数扩展这个语法是真的难找,往上的资料都很少,文档也少,也可能是我查找的关键词不够准确。