Ubuntu 22.04 LTS 服务器 SSH 密钥配置与自动化部署实践
1. 从零开始为什么SSH密钥是服务器管理的基石如果你刚接触服务器运维或者还在用密码登录你的Ubuntu 22.04服务器那今天这篇分享可能会彻底改变你的工作流。我管理过上百台服务器从早期的密码登录到后来的密钥认证再到现在的全自动化部署可以说SSH密钥是通往高效、安全运维世界的第一张门票。密码登录就像用一把简单的挂锁看门而SSH密钥则相当于配备了生物识别和动态密码的智能门禁系统安全性不在一个量级。简单来说SSH密钥是一对数学上关联的“钥匙”一把叫私钥你把它安全地保管在自己的电脑上绝不外传另一把叫公钥你可以把它放到任何你想登录的服务器上。当你想连接服务器时服务器会用你放上去的公钥出一道“数学题”只有你手里对应的私钥才能解开。这个过程完全不需要你在网络上传输密码从根本上杜绝了密码被窃听、暴力破解的风险。在自动化场景里比如用脚本批量部署应用、用CI/CD工具自动发布代码你不可能每次都手动输密码SSH密钥就成了实现“无人值守”自动登录的唯一选择。Ubuntu 22.04 LTS作为长期支持版本其SSH服务OpenSSH非常成熟稳定为我们提供了绝佳的基础。但很多教程只讲到“生成密钥、复制到服务器”就结束了这仅仅是开始。真正的价值在于如何把这一步操作融入到成百上千台服务器的规模化管理和自动化流程中。接下来我会手把手带你走完从单机配置到自动化部署的完整路径分享一些我踩过坑才总结出来的实战经验。2. 本地环境生成你的第一对SSH密钥万事开头难但生成SSH密钥可能是整个流程里最简单的一步。打开你本地电脑的终端无论是Windows上的WSL、macOS的Terminal还是Linux的Shell我们开始操作。2.1 密钥生成命令的细节与选择最基础的命令是ssh-keygen。直接输入它并回车系统会开始交互式提问。但作为自动化准备的我们更应该了解如何用一行命令搞定所有参数。我常用的命令是这样的ssh-keygen -t ed25519 -C your_emailexample.com -f ~/.ssh/id_ed25519_myproject -N 我来拆解一下这几个参数-t ed25519: 这是指定密钥的算法。相比传统的RSAEd25519是更现代、更安全、生成更快且密钥更短的选择。在Ubuntu 22.04的OpenSSH中它被广泛支持。如果你有必须使用RSA的旧系统兼容需求可以用-t rsa -b 4096来生成一个4096位的强RSA密钥。-C your_emailexample.com: 这是给密钥加一个注释通常用你的邮箱方便日后识别这把钥匙是谁的、用于什么用途。这在管理多对密钥时特别有用。-f ~/.ssh/id_ed25519_myproject: 指定密钥文件的存放路径和名称。我强烈建议你不要使用默认的id_rsa而是根据项目或用途命名比如id_ed25519_work、id_ed25519_github。这为后续管理多密钥对打下了基础。-N : 设置一个空密码。这是一个需要根据场景权衡的安全决策。对于完全自动化的流程如CI/CD流水线密钥文件本身需要被脚本直接读取不能有交互式密码提示所以设为空。但对于个人电脑上用于登录生产服务器的密钥我强烈建议设置一个强密码即去掉-N 让系统提示你输入这样即使私钥文件意外泄露没有密码也无法使用。执行命令后你会在~/.ssh/目录下看到两个文件id_ed25519_myproject私钥权限必须是600和id_ed25519_myproject.pub公钥内容是一长串文本。请像保护银行卡密码一样保护你的私钥文件。2.2 管理多密钥对与SSH Agent当你为不同服务器、不同平台如GitHub、GitLab准备了多对密钥后就需要告诉SSH客户端在连接不同主机时使用哪把钥匙。这就要配置~/.ssh/config文件。这个文件可能不存在你可以用touch ~/.ssh/config创建它。下面是一个配置示例# 我的个人VPS服务器 Host myserver HostName 192.168.1.100 # 或你的域名 User ubuntu IdentityFile ~/.ssh/id_ed25519_personal Port 22 # 公司生产服务器 Host company-prod HostName prod.example.com User deploy IdentityFile ~/.ssh/id_ed25519_company_prod Port 2222 # 非标准端口 # 匹配所有GitHub域名使用特定密钥 Host github.com User git IdentityFile ~/.ssh/id_ed25519_github配置好后你登录服务器就不再需要输入ssh ubuntu192.168.1.100而是直接输入ssh myserverSSH客户端会自动使用对应的密钥和用户名非常方便。对于设置了密码的私钥每次使用都要输入密码也很麻烦。这时可以启动ssh-agent这个密钥管家。你可以通过eval $(ssh-agent -s)启动代理然后用ssh-add ~/.ssh/id_ed25519_personal将私钥添加进去并输入一次密码。之后在当前终端会话中再使用该密钥就无需重复输入密码了。很多桌面环境会自动启动并管理ssh-agent。3. 服务器端配置加固你的Ubuntu 22.04 SSH服务现在我们假设你已经通过密码登录到了一台全新的Ubuntu 22.04 LTS服务器上。我们的目标是将你的公钥部署上去并让SSH服务只认钥匙不认密码。3.1 部署公钥的几种姿势最优雅的方式是使用ssh-copy-id命令前提是你的本地机器上有这个工具大多数Linux发行版和macOS都有。命令非常简单ssh-copy-id -i ~/.ssh/id_ed25519_myproject.pub usernameserver_ip-i参数指定你的公钥文件路径。执行后输入一次服务器密码你的公钥就会被自动追加到服务器对应用户家目录下的~/.ssh/authorized_keys文件中。这是最推荐新手使用的方法。如果因为某些原因没有ssh-copy-id我们可以用一条经典的SSH管道命令手动完成这条命令体现了Linux的哲学——“一切皆文件组合出奇迹”cat ~/.ssh/id_ed25519_myproject.pub | ssh usernameserver_ip mkdir -p ~/.ssh chmod 700 ~/.ssh cat ~/.ssh/authorized_keys chmod 600 ~/.ssh/authorized_keys这条命令做了以下几件事1. 本地读取公钥内容2. 通过SSH连接到服务器3. 在服务器上创建.ssh目录如果不存在并设置严格权限4. 将公钥内容追加到authorized_keys文件末尾5. 确保该文件权限正确。注意authorized_keys文件的权限必须非常严格通常要求是600仅所有者可读写其所在的~/.ssh目录权限通常是700。权限过宽会导致SSH出于安全考虑拒绝使用密钥登录。3.2 关键的SSH服务安全加固在测试密钥登录成功之前千万不要急着关闭密码登录。你需要先打开另一个终端窗口用ssh -i /path/to/private/key usernameserver_ip的方式指定私钥进行连接测试确保万无一失。确认密钥登录畅通无阻后我们就可以进行服务器端的SSH安全加固了。用sudo nano /etc/ssh/sshd_config编辑SSH守护进程的配置文件。下面是我通常会修改的几个关键参数# 禁止root用户直接SSH登录降低风险 PermitRootLogin no # 禁用密码认证强制使用密钥 PasswordAuthentication no # 启用公钥认证 PubkeyAuthentication yes # 可选限制允许登录的用户多个用户用空格隔开 AllowUsers ubuntu deploy_user # 可选更改默认端口减少自动化攻击扫描修改后记得配置防火墙 # Port 2222 # 可选限制最大认证尝试次数应对暴力破解 MaxAuthTries 3 # 可选设置客户端存活检测避免僵死连接占用资源 ClientAliveInterval 300 ClientAliveCountMax 2每修改一项你都要清楚它的含义。比如改端口你就得记住新端口号并且要在服务器的防火墙如UFW中开放这个新端口。修改完成后使用sudo systemctl reload ssh或sudo systemctl restart ssh重新加载配置。reload是热重载不会断开现有连接更安全restart是重启服务。再次强调务必在开着一个有效的SSH会话窗口的情况下新开一个窗口测试所有新配置是否生效确认无误后再关闭原来的会话。否则一个配置失误就可能把自己关在服务器门外。4. 自动化部署实战用Ansible批量管理SSH密钥当服务器数量从一台变成十台、一百台时手动登录每一台去跑命令就变成了灾难。这时自动化配置工具就成了必备品。在众多工具中Ansible因其无需在目标服务器安装客户端仅需SSH和Python的特性成为自动化运维的明星。下面我就以Ansible为例展示如何批量部署SSH密钥。4.1 Ansible基础与清单配置首先在你的管理机可以是你的笔记本电脑也可以是一台专门的“控制节点”上安装Ansible。在Ubuntu上很简单sudo apt update sudo apt install ansible -y。Ansible通过一个“清单”文件来管理你要操作的所有服务器。我们创建一个简单的文本文件比如叫inventory.ini[web_servers] web1 ansible_host192.168.1.101 ansible_userubuntu web2 ansible_host192.168.1.102 ansible_userubuntu [db_servers] db1 ansible_host192.168.1.201 ansible_userubuntu [all:vars] # 假设所有服务器都使用同一对密钥进行Ansible连接 ansible_ssh_private_key_file~/.ssh/id_ed25519_ansible # 禁用host key检查在首次批量部署时比较方便生产环境可考虑其他策略 ansible_ssh_common_args-o StrictHostKeyCheckingno这个清单定义了两个组web_servers和db_servers并为所有主机设置了连接用的私钥路径。4.2 编写Ansible Playbook部署密钥Playbook是Ansible的剧本用YAML语法编写描述了你要在目标服务器上执行的一系列任务。我们创建一个deploy_ssh_keys.yml文件--- - name: 为运维团队部署SSH公钥 hosts: all # 对所有清单中的主机执行 become: yes # 以sudo权限执行 tasks: - name: 确保.ssh目录存在并设置正确权限 ansible.builtin.file: path: /home/{{ ansible_user }}/.ssh state: directory mode: 0700 owner: {{ ansible_user }} group: {{ ansible_user }} - name: 将本地公钥文件内容部署到服务器的authorized_keys ansible.builtin.copy: content: {{ lookup(file, ~/.ssh/id_ed25519_team.pub) }} dest: /home/{{ ansible_user }}/.ssh/authorized_keys owner: {{ ansible_user }} group: {{ ansible_user }} mode: 0600 # 注意这个任务会覆盖原有的authorized_keys文件。 # 如果想追加可以使用lineinfile模块但管理多人密钥更推荐使用专门的authorized_keys模块。 - name: 禁用SSH密码认证危险请确保密钥登录已测试成功 ansible.builtin.lineinfile: path: /etc/ssh/sshd_config regexp: ^#?PasswordAuthentication line: PasswordAuthentication no state: present notify: restart ssh handlers: - name: restart ssh ansible.builtin.systemd: name: ssh state: restarted enabled: yes这个Playbook做了三件事1. 创建并设置.ssh目录2. 将你本地id_ed25519_team.pub文件的内容写入到服务器对应用户的authorized_keys文件这里用了copy模块的content参数直接传递内容3. 修改SSH配置禁用密码登录并在修改后触发一个“处理器”来重启SSH服务。警告上面第二个任务会覆盖目标服务器上原有的authorized_keys文件。如果你是要为多个运维人员添加密钥应该使用ansible.posix.authorized_key模块或者采用追加的方式。覆盖操作只在你完全控制该服务器初始配置时使用。运行这个Playbook的命令是ansible-playbook -i inventory.ini deploy_ssh_keys.yml。Ansible会依次连接清单中的所有服务器并执行剧本中的任务。你会看到清晰的输出显示每台服务器的任务执行结果是成功ok还是变更changed。4.3 更复杂的场景为不同服务器组部署不同密钥在实际项目中你可能希望Web服务器组使用一套密钥数据库服务器组使用另一套密钥。利用Ansible的组变量可以轻松实现。我们可以在Playbook中通过when条件判断或者更优雅地在清单文件中或group_vars/目录下为不同组定义变量。例如在inventory.ini中直接为组定义变量[web_servers] web1 ansible_host192.168.1.101 web2 ansible_host192.168.1.102 [web_servers:vars] ssh_public_key_file~/.ssh/id_ed25519_web [db_servers] db1 ansible_host192.168.1.201 [db_servers:vars] ssh_public_key_file~/.ssh/id_ed25519_db然后在Playbook中任务可以引用{{ ssh_public_key_file }}这个变量Ansible会根据当前正在操作的主机所属的组自动选择对应的公钥文件路径。这种灵活性让管理成百上千台异构服务器变得井井有条。5. 进阶与排坑密钥管理中的实战经验自动化不是一劳永逸在实际运维中你会遇到各种边界情况和挑战。分享几个我踩过的坑和解决方案。密钥轮换与撤销密钥和密码一样需要定期更换。你不能直接删除服务器上的公钥就完事因为可能还有人在用。一个稳妥的做法是在authorized_keys文件中你可以为每行公钥添加选项比如from192.168.1.0/24来限制来源IP。当需要撤销某个密钥时先在这一行公钥前添加revoked之类的注释标记观察一段时间无影响后再删除。Ansible的authorized_key模块的state: absent属性可以帮你从多台服务器上精确删除某条指定的公钥。权限问题导致的连接失败这是新手最常见的坑。除了之前提到的~/.ssh目录权限必须是700authorized_keys文件权限必须是600外还要注意用户家目录的权限也不能太开放。如果家目录如/home/ubuntu的权限是775组和其他用户可读SSH出于安全考虑也会拒绝密钥登录。通常家目录权限设为755或750是安全的。调试SSH连接当密钥登录失败时别慌。在客户端使用ssh -vvv userhost命令会输出极其详细的调试信息你可以看到SSH连接每一步的进展到底是在哪一步认证失败了。在服务器端可以查看/var/log/auth.log文件里面记录了SSH登录的详细日志包括失败的尝试和原因。在CI/CD流水线中使用SSH密钥在GitLab CI、GitHub Actions或Jenkins中你需要将私钥通常是去掉密码的以“密钥变量”或“Secret”的形式存储然后在流水线脚本中写入到一个临时文件并通过ssh -i指定使用。务必确保流水线运行结束后清理临时私钥文件。一个常见的做法是使用ssh-agent在流水线步骤中临时管理密钥。# GitHub Actions 示例片段 - name: 配置SSH密钥部署到服务器 run: | mkdir -p ~/.ssh echo ${{ secrets.SSH_PRIVATE_KEY }} ~/.ssh/deploy_key chmod 600 ~/.ssh/deploy_key ssh -o StrictHostKeyCheckingno -i ~/.ssh/deploy_key userhost echo deploy success最后关于安全性的再提醒用于自动化流程的私钥其访问权限必须严格控制。服务器上的authorized_keys文件可以结合command选项限制该密钥只能运行特定的命令而不是获得一个完整的shell这能极大提升安全性。例如command/usr/bin/git-receive-pack /path/to/repo.git ssh-ed25519 AAAAB3...这样即使密钥泄露攻击者也只能执行固定的Git操作无法执行任意命令。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2419524.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!