core: 支持设置 ssh 公钥登录

close #134
This commit is contained in:
bin456789 2025-03-06 20:45:30 +08:00
parent f8ca315d71
commit eb98bc34a2
No known key found for this signature in database
GPG Key ID: EE301B386DE6C11B
5 changed files with 231 additions and 46 deletions

View File

@ -150,6 +150,14 @@ bash reinstall.sh anolis 7|8|23
#### Optional Parameters
- `--password PASSWORD` Set the password
- `--ssh-key KEY` Set up SSH public key, supports these formats. When using public key, password is empty.
- `--ssh-key "ssh-rsa ..."`
- `--ssh-key "ssh-ed25519 ..."`
- `--ssh-key "ecdsa-sha2-nistp256/384/521 ..."`
- `--ssh-key http://url`
- `--ssh-key github:your_username`
- `--ssh-key gitlab:your_username`
- `--ssh-key /path/to/public_key`
- `--ssh-port PORT` Change the SSH port (for log observation during installation and for the new system)
- `--web-port PORT` Change the Web port (for log observation during installation)
- `--hold 2` Prevent reboot after installation completes, allowing SSH login to modify system content; the system is mounted at `/os` (this feature is not supported on Debian/Kali).
@ -228,6 +236,14 @@ bash reinstall.sh alpine --hold=1
- `--password PASSWORD` Set password
- `--ssh-port PORT` Change SSH port
- `--ssh-key KEY` Set up SSH public key, supports these formats. When using public key, password is empty.
- `--ssh-key ssh-rsa ...`
- `--ssh-key ssh-ed25519 ...`
- `--ssh-key ecdsa-sha2-nistp256/384/521 ...`
- `--ssh-key http://url`
- `--ssh-key github:your_username`
- `--ssh-key gitlab:your_username`
- `--ssh-key /path/to/public_key`
### Feature 4: Reboot to <img width="16" height="16" src="https://netboot.xyz/img/favicon.ico" /> netboot.xyz

View File

@ -150,7 +150,15 @@ bash reinstall.sh anolis 7|8|23
#### 可选参数
- `--password PASSWORD` 设置密码
- `--ssh-port PORT` 修改 SSH 端口(安装期间观察日志用,也用于新系统)
- `--ssh-key KEY` 设置 SSH 公钥登录,支持以下格式。当使用公钥时,密码为空
- `--ssh-key "ssh-rsa ..."`
- `--ssh-key "ssh-ed25519 ..."`
- `--ssh-key "ecdsa-sha2-nistp256/384/521 ..."`
- `--ssh-key http://url`
- `--ssh-key github:your_username`
- `--ssh-key gitlab:your_username`
- `--ssh-key /path/to/public_key`
- `--ssh-port PORT` 修改 SSH 端口(安装期间观察日志用,也作用于新系统)
- `--web-port PORT` 修改 Web 端口(安装期间观察日志用)
- `--hold 2` 安装结束后不重启,此时可以 SSH 登录修改系统内容,系统挂载在 `/os` (此功能不支持 Debian/Kali)
@ -228,6 +236,14 @@ bash reinstall.sh alpine --hold=1
- `--password PASSWORD` 设置密码
- `--ssh-port PORT` 修改 SSH 端口
- `--ssh-key KEY` 设置 SSH 公钥登录,支持以下格式。当使用公钥时,密码为空
- `--ssh-key ssh-rsa ...`
- `--ssh-key ssh-ed25519 ...`
- `--ssh-key ecdsa-sha2-nistp256/384/521 ...`
- `--ssh-key http://url`
- `--ssh-key github:your_username`
- `--ssh-key gitlab:your_username`
- `--ssh-key /path/to/public_key`
### 功能 4: 重启到 <img width="16" height="16" src="https://netboot.xyz/img/favicon.ico" /> netboot.xyz

View File

@ -26,6 +26,7 @@ d-i mirror/country string manual
# B.4.5. 帐号设置
d-i passwd/make-user boolean false
# 单纯为了跳过设置,实际上是在 partman/early_command 里设置密码preseed/early_command 无法设置密码
# 注意如果用 ssh key 后面还要删除密码
d-i passwd/root-password password ''
d-i passwd/root-password-again password ''
# kali 需要下面这行,否则会提示输入用户名
@ -172,8 +173,13 @@ d-i preseed/late_command string true; \
in-target systemctl enable ssh; \
echo "PermitRootLogin yes" >/target/etc/ssh/sshd_config.d/01-permitrootlogin.conf || \
echo "PermitRootLogin yes" >>/target/etc/ssh/sshd_config; \
if [ -s /configs/ssh_keys ]; then \
(umask 077; mkdir -p /target/root/.ssh; cat /configs/ssh_keys >/target/root/.ssh/authorized_keys); \
in-target passwd -d root; \
else \
echo "PermitRootLogin yes" >/target/etc/ssh/sshd_config.d/01-permitrootlogin.conf || \
echo "PermitRootLogin yes" >>/target/etc/ssh/sshd_config; \
fi; \
if [ -n "$ssh_port" ] && ! [ "$ssh_port" = 22 ]; then \
echo "Port $ssh_port" >/target/etc/ssh/sshd_config.d/01-change-ssh-port.conf || \

View File

@ -69,7 +69,9 @@ Usage: $reinstall_____ anolis 7|8|23
windows --image-name="windows xxx yyy" --iso="http://xxx.com/xxx.iso"
netboot.xyz
Options: [--ssh-port PORT]
Options: [--password PASSWORD]
[--ssh-key KEY]
[--ssh-port PORT]
[--rdp-port PORT]
[--web-port PORT]
[--allow-ping]
@ -1790,6 +1792,10 @@ verify_os_args() {
redhat) [ -n "$img" ] || error_and_exit "redhat need --img" ;;
windows) [ -n "$image_name" ] || error_and_exit "Install Windows need --image-name." ;;
esac
case "$distro" in
netboot.xyz | windows) [ -z "$ssh_keys" ] || error_and_exit "not support ssh key for $distro" ;;
esac
}
get_cmd_path() {
@ -3471,7 +3477,11 @@ This script is outdated, please download reinstall.sh again.
# 保存配置
mkdir -p $initrd_dir/configs
save_password $initrd_dir/configs
if [ -n "$ssh_keys" ]; then
cat <<<"$ssh_keys" >$initrd_dir/configs/ssh_keys
else
save_password $initrd_dir/configs
fi
if is_distro_like_debian $nextos_distro; then
mod_initrd_debian_kali
@ -3572,6 +3582,15 @@ remove_useless_initrd_files() {
du -sh .
}
get_unix_path() {
if is_in_windows; then
# 输入的路径是 / 开头也没问题
cygpath -u "$1"
else
printf '%s' "$1"
fi
}
# 脚本入口
if mount | grep -q 'tmpfs on / type tmpfs'; then
error_and_exit "Can't run this script in Live OS."
@ -3620,6 +3639,7 @@ for o in ci installer debug minimal allow-ping force-cn \
lang: \
passwd: password: \
ssh-port: \
ssh-key: public-key: \
rdp-port: \
web-port: http-port: \
allow-ping: \
@ -3687,6 +3707,73 @@ while true; do
--passwd | --password)
[ -n "$2" ] || error_and_exit "Need value for $1"
password=$2
shift 2
;;
--ssh-key | --public-key)
ssh_key_error_and_exit() {
error "$1"
cat <<EOF
Available options:
--ssh-key "ssh-rsa ..."
--ssh-key "ssh-ed25519 ..."
--ssh-key "ecdsa-sha2-nistp256/384/521 ..."
--ssh-key github:your_username
--ssh-key gitlab:your_username
--ssh-key http://url
--ssh-key https://url
--ssh-key /path/to/public_key
EOF
exit 1
}
# https://manpages.debian.org/testing/openssh-server/authorized_keys.5.en.html#AUTHORIZED_KEYS_FILE_FORMAT
is_valid_ssh_key() {
grep -qE '^(ecdsa-sha-nistp(256|384|512)|ssh-(ed25519|rsa)) ' <<<"$1"
}
[ -n "$2" ] || ssh_key_error_and_exit "Need value for $1"
case "$(to_lower <<<"$2")" in
github:* | gitlab:* | http://* | https://*)
if [[ "$(to_lower <<<"$2")" = http* ]]; then
key_url=$2
else
IFS=: read -r site user <<<"$2"
[ -n "$user" ] || ssh_key_error_and_exit "Need a username for $site"
key_url="https://$site.com/$user.keys"
fi
if ! ssh_key=$(curl -L "$key_url"); then
error_and_exit "Can't get ssh key from $key_url"
fi
;;
*)
# 检测值是否为 ssh key
if is_valid_ssh_key "$2"; then
ssh_key=$2
else
# 视为路径
# windows 路径转换
if ! { ssh_key_file=$(get_unix_path "$2") && [ -f "$ssh_key_file" ]; }; then
ssh_key_error_and_exit "SSH Key/File/Url \"$2\" is invalid."
fi
ssh_key=$(<"$ssh_key_file")
fi
;;
esac
# 检查 key 格式
if ! is_valid_ssh_key "$ssh_key"; then
ssh_key_error_and_exit "SSH Key/File/Url \"$2\" is invalid."
fi
# 保存 key
# 不用处理注释,可以支持写入 authorized_keys
# 安装 nixos 时再处理注释/空行,转成数组,再添加到 nix 配置文件中
if [ -n "$ssh_keys" ]; then
ssh_keys+=$'\n'
fi
ssh_keys+=$ssh_key
shift 2
;;
--ssh-port)
@ -3705,13 +3792,10 @@ while true; do
shift 2
;;
--add-driver)
# 路径转换
if is_in_windows; then
# 输入的路径是 / 开头也没问题
inf_or_dir="$(cygpath -u "$2")"
else
inf_or_dir=$2
fi
[ -n "$2" ] || error_and_exit "Need value for $1"
# windows 路径转换
inf_or_dir=$(get_unix_path "$2")
# alpine busybox 不支持 readlink -m
# readlink -m /asfsafasfsaf/fasf
@ -3719,7 +3803,7 @@ while true; do
if ! [ -d "$inf_or_dir" ] &&
! { [ -f "$inf_or_dir" ] && [[ "$inf_or_dir" =~ \.[iI][nN][fF]$ ]]; }; then
error_and_exit "Not a inf or dir: $2"
ssh_key_error_and_exit "Not a inf or dir: $2"
fi
# 转为绝对路径
@ -3795,7 +3879,7 @@ if is_secure_boot_enabled; then
fi
# 密码
if ! is_netboot_xyz && [ -z "$password" ]; then
if ! is_netboot_xyz && [ -z "$ssh_keys" ] && [ -z "$password" ]; then
if is_use_dd; then
echo "
This password is only used for SSH access to view logs during the installation.
@ -4234,14 +4318,19 @@ fi
info 'info'
echo "$distro $releasever"
if ! { is_netboot_xyz || is_use_dd || [ "$distro" = fnos ]; }; then
if [ "$distro" = windows ]; then
username="administrator"
else
username="root"
fi
case "$distro" in
windows) username=administrator ;;
dd | netboot.xyz) username= ;;
*) username=root ;;
esac
if [ -n "$username" ]; then
echo "Username: $username"
echo "Password: $password"
if [ -n "$ssh_keys" ]; then
echo "Public Key: $ssh_keys"
else
echo "Password: $password"
fi
fi
if is_netboot_xyz; then

108
trans.sh
View File

@ -536,6 +536,7 @@ set_config() {
printf '%s' "$2" >"/configs/$1"
}
# ubuntu 安装版、el/ol 安装版不使用该密码
get_password_linux_sha512() {
get_config password-linux-sha512
}
@ -544,7 +545,6 @@ get_password_windows_administrator_base64() {
get_config password-windows-administrator-base64
}
# debian 安装版、ubuntu 安装版、el/ol 安装版不使用该密码
get_password_plaintext() {
get_config password-plaintext
}
@ -726,6 +726,10 @@ is_elts() {
[ -n "$elts" ] && [ "$elts" = 1 ]
}
is_need_set_ssh_keys() {
[ -s /configs/ssh_keys ]
}
is_need_change_ssh_port() {
[ -n "$ssh_port" ] && ! [ "$ssh_port" = 22 ]
}
@ -771,6 +775,10 @@ del_cr() {
sed 's/\r//g'
}
del_comment_lines() {
sed '/^[[:space:]]*#/d'
}
del_empty_lines() {
sed '/^[[:space:]]*$/d'
}
@ -1376,6 +1384,11 @@ install_alpine() {
chroot /os setup-timezone -i Asia/Shanghai
chroot /os setup-ntp chrony || true
# 设置公钥
if is_need_set_ssh_keys; then
set_ssh_keys_and_del_password /os
fi
# 下载 fix-eth-name
download "$confhome/fix-eth-name.sh" /os/fix-eth-name.sh
download "$confhome/fix-eth-name.initd" /os/etc/init.d/fix-eth-name
@ -1571,6 +1584,17 @@ install_nixos() {
if [ -e /os/swapfile ] && $keep_swap; then
nix_swap="swapDevices = [{ device = \"/swapfile\"; size = $swap_size; }];"
fi
if is_need_set_ssh_keys; then
nix_ssh_keys_or_PermitRootLogin="
users.users.root.openssh.authorizedKeys.keys = [
$(del_comment_lines </configs/ssh_keys | del_empty_lines | quote_line | add_space 2)
];
"
else
nix_ssh_keys_or_PermitRootLogin='services.openssh.settings.PermitRootLogin = "yes";'
fi
if is_need_change_ssh_port; then
nix_ssh_ports="services.openssh.ports = [ $ssh_port ];"
fi
@ -1585,7 +1609,7 @@ $nix_swap
$nix_substituters
boot.kernelParams = [ $(get_ttys console= | quote_word) ];
services.openssh.enable = true;
services.openssh.settings.PermitRootLogin = "yes";
$nix_ssh_keys_or_PermitRootLogin
$nix_ssh_ports
$(cat /tmp/nixos_network_config.nix)
###################################################
@ -1632,8 +1656,10 @@ EOF
nixos-install --root /os --no-root-passwd -j $threads
# 设置密码
echo "root:$(get_password_linux_sha512)" | nixos-enter --root /os -- \
/run/current-system/sw/bin/chpasswd -e
if ! is_need_set_ssh_keys; then
echo "root:$(get_password_linux_sha512)" | nixos-enter --root /os -- \
/run/current-system/sw/bin/chpasswd -e
fi
# 设置 channel
if is_in_china; then
@ -1726,14 +1752,18 @@ basic_init() {
done
fi
allow_root_password_login $os_dir
allow_password_login $os_dir
if is_need_change_ssh_port; then
change_ssh_port $os_dir $ssh_port
fi
# 修改密码
change_root_password $os_dir
# 公钥/密码
if is_need_set_ssh_keys; then
set_ssh_keys_and_del_password $os_dir
else
change_root_password $os_dir
allow_root_password_login $os_dir
allow_password_login $os_dir
fi
# 下载 fix-eth-name.service
# 即使开了 net.ifnames=0 也需要
@ -3419,7 +3449,7 @@ EOF
# 在这里修改密码而不是用cloud-init因为我们的默认密码太弱
is_password_plaintext && sed -i 's/enforce=everyone/enforce=none/' $os_dir/etc/security/passwdqc.conf
echo "root:$(get_password_linux_sha512)" | chroot $os_dir chpasswd -e
change_root_password $os_dir
is_password_plaintext && sed -i 's/enforce=none/enforce=everyone/' $os_dir/etc/security/passwdqc.conf
# 下载仓库,选择 profile
@ -3555,6 +3585,21 @@ create_swap() {
fi
}
set_ssh_keys_and_del_password() {
os_dir=$1
info 'set ssh keys'
# 添加公钥
(
umask 077
mkdir -p $os_dir/root/.ssh
cat /configs/ssh_keys >$os_dir/root/.ssh/authorized_keys
)
# 删除密码
chroot $os_dir passwd -d root
}
# 除了 alpine 都会用到
change_ssh_conf() {
os_dir=$1
@ -3562,20 +3607,25 @@ change_ssh_conf() {
value=$3
sub_conf=$4
# arch 没有 /etc/ssh/sshd_config.d/ 文件夹
# opensuse tumbleweed 没有 /etc/ssh/sshd_config
# 有 /etc/ssh/sshd_config.d/ 文件夹
# 有 /usr/etc/ssh/sshd_config
if { grep -q 'Include.*/etc/ssh/sshd_config.d' $os_dir/etc/ssh/sshd_config ||
grep -q '^Include.*/etc/ssh/sshd_config.d/' $os_dir/usr/etc/ssh/sshd_config; } 2>/dev/null; then
if line="^$key .*" && grep -Exq "$line" $os_dir/etc/ssh/sshd_config; then
# 如果 sshd_config 存在此 key非注释状态则替换
sed -Ei "s/$line/$key $value/" $os_dir/etc/ssh/sshd_config
elif {
# arch 没有 /etc/ssh/sshd_config.d/ 文件夹
# opensuse tumbleweed 没有 /etc/ssh/sshd_config
# 有 /etc/ssh/sshd_config.d/ 文件夹
# 有 /usr/etc/ssh/sshd_config
grep -q 'Include.*/etc/ssh/sshd_config.d' $os_dir/etc/ssh/sshd_config ||
grep -q '^Include.*/etc/ssh/sshd_config.d/' $os_dir/usr/etc/ssh/sshd_config
} 2>/dev/null; then
mkdir -p $os_dir/etc/ssh/sshd_config.d/
echo "$key $value" >"$os_dir/etc/ssh/sshd_config.d/$sub_conf"
else
# 如果 sshd_config 存在此 key则替换
# 如果 sshd_config 存在此 key (无论是否已注释),则替换,包括删除注释
# 否则追加
line="^#?$key .*"
if grep -Exq "$line" $os_dir/etc/ssh/sshd_config; then
sed -Eiq "s/$line/$key $value/" $os_dir/etc/ssh/sshd_config
sed -Ei "s/$line/$key $value/" $os_dir/etc/ssh/sshd_config
else
echo "$key $value" >>$os_dir/etc/ssh/sshd_config
fi
@ -3584,17 +3634,15 @@ change_ssh_conf() {
allow_password_login() {
os_dir=$1
change_ssh_conf "$os_dir" PasswordAuthentication yes 02-PasswordAuthenticaton.conf
change_ssh_conf "$os_dir" PasswordAuthentication yes 01-PasswordAuthenticaton.conf
}
# arch gentoo 常规安装用
allow_root_password_login() {
os_dir=$1
change_ssh_conf "$os_dir" PermitRootLogin yes 01-permitrootlogin.conf
}
# arch gentoo 常规安装用
change_ssh_port() {
os_dir=$1
ssh_port=$2
@ -3974,8 +4022,11 @@ install_fnos() {
# chroot $os_dir update-initramfs -u
# 更改密码
# chroot $os_dir passwd -d root
echo "root:$(get_password_linux_sha512)" | chroot $os_dir chpasswd -e
if is_need_set_ssh_keys; then
set_ssh_keys_and_del_password $os_dir
else
change_root_password $os_dir
fi
# ssh root 登录,测试用
if false; then
@ -6328,13 +6379,20 @@ mount / -o remount,size=100%
# 4. 允许同步失败,因为不是关键步骤
sync_time || true
# 设置密码,安装并打开 ssh
echo "root:$(get_password_linux_sha512)" | chpasswd -e
# 安装 ssh 并更改端口
apk add openssh
if is_need_change_ssh_port; then
change_ssh_port / $ssh_port
fi
printf '\nyes' | setup-sshd
# 设置密码,添加开机启动 + 开启 ssh 服务
if is_need_set_ssh_keys; then
set_ssh_keys_and_del_password /
printf '\n' | setup-sshd
else
change_root_password /
printf '\nyes' | setup-sshd
fi
# shellcheck disable=SC2154
if [ "$hold" = 1 ]; then