Python (Ansbile)脚本高效批量管理服务器和安全

1、简介

在现代 IT 基础设施中,管理大量服务器是一项复杂而繁琐的任务。特别是在检查服务器的存活状态以及 SSH 登录等任务上,手动操作非常耗时且容易出错。本文将介绍如何使用 Python 脚本实现对多台服务器的批量检查和管理,包括检查服务器是否在线,以及通过密码或 SSH 密钥登录服务器。

2、背景

在我们测试机房环境,为了方便管理和使用。需要统一 账号,登录方式,以及堡垒机安全验证。在之前架构基础上,我们需要梳理整合现有所有测试机器。
需要批量管理和监控多台服务器。例如,检查服务器是否存活、是否可以通过 SSH 登录等。手动执行这些任务效率低且容易出错。通过编写自动化脚本,可以大大提高工作效率和准确性。

3、环境介绍

1、依赖库

  1. paramiko:用于 SSH 登录。
  2. tqdm:用于显示进度条。
  3. concurrent.futures:用于多线程处理。

可以通过以下命令安装这些库:

pip install paramiko tqdm

2、文件结构

  • hosts:包含服务器 IP 地址的文件,每行一个 IP 地址。
  • ssh_key:SSH 私钥文件路径。
  • script.py:主脚本文件。
    在这里插入图片描述

4、Python实现步骤

方便统计使用,归档文件 后期整理维护

第一步:读取 IP 地址

首先,我们需要读取 hosts 文件中的 IP 地址。每行一个 IP 地址。

# 读取 IP 地址
with open('hosts', 'r') as file:ip_addresses = [line.strip() for line in file.readlines()]

第二步:检查 IP 是否存活

我们使用 ping 命令检查每个 IP 是否存活。通过 subprocess 模块执行 ping 命令,并检查返回码来判断 IP 是否存活。

import subprocessdef is_alive(ip):try:  #这里注意判断# For Unix/Linux/Macresult = subprocess.run(['ping', '-c', '1', ip], stdout=subprocess.PIPE, stderr=subprocess.PIPE)except FileNotFoundError:# For Windowsresult = subprocess.run(['ping', '-n', '1', ip], stdout=subprocess.PIPE, stderr=subprocess.PIPE)return result.returncode == 0

第三步:尝试 SSH 登录

我们使用 paramiko 库尝试通过密码和 SSH 密钥登录服务器。为了处理 RSA 格式的密钥,我们使用 paramiko.RSAKey.from_private_key_file 函数。

import paramiko
from paramiko import SSHClient, AutoAddPolicy, RSAKeydef ssh_login_with_password(ip, username, password):try:client = SSHClient()client.set_missing_host_key_policy(AutoAddPolicy())client.connect(ip, username=username, password=password, timeout=5)client.close()return Trueexcept Exception as e:return Falsedef ssh_login_with_key(ip, username, key_path):try:client = SSHClient()client.set_missing_host_key_policy(AutoAddPolicy())key = RSAKey.from_private_key_file(key_path)client.connect(ip, username=username, pkey=key, timeout=5)client.close()return Trueexcept Exception as e:return False

第四步:并行处理 IP 地址

为了提高效率,我们使用 concurrent.futures.ThreadPoolExecutor 实现多线程处理。每个线程会检查一个 IP 的存活状态,并尝试通过密码和 SSH 密钥登录。

from concurrent.futures import ThreadPoolExecutor, as_completed
from tqdm import tqdmdef check_ip(ip):if not is_alive(ip):return ('non_alive', ip)else:if ssh_login_with_password(ip, USERNAME, PASSWORD):return ('ssh_password_success', ip)elif ssh_login_with_key(ip, USERNAME, KEY_PATH):return ('ssh_key_success', ip)else:return ('ssh_failures', ip)with ThreadPoolExecutor(max_workers=10) as executor:futures = {executor.submit(check_ip, ip): ip for ip in ip_addresses}for future in tqdm(as_completed(futures), total=len(ip_addresses), desc="Checking IPs"):result, ip = future.result()if result == 'non_alive':non_alive_ips.append(ip)elif result == 'ssh_password_success':ssh_password_success.append(ip)elif result == 'ssh_key_success':ssh_key_success.append(ip)elif result == 'ssh_failures':ssh_failures.append(ip)

第五步:生成结果文件

最后,我们将检查结果写入一个文件中,按照指定的格式记录每个 IP 的状态。

# 写入结果到文件
with open('output.txt', 'w') as output_file:output_file.write("[no_alive]\n")output_file.write("\n".join(non_alive_ips) + "\n")output_file.write("[password]\n")output_file.write("\n".join(ssh_password_success) + "\n")output_file.write("[key]\n")output_file.write("\n".join(ssh_key_success) + "\n")output_file.write("[fail]\n")output_file.write("\n".join(ssh_failures) + "\n")print("Results have been written to output.txt")

完整的代码

# -*- coding: utf-8 -*-
# @Time    : 2024-06-27 11:46
# @Author  : 南宫乘风
# @Email   : 1794748404@qq.com
# @File    : kvm.py
# @Software: PyCharm
import os
import subprocess
from paramiko import SSHClient, AutoAddPolicy
from tqdm import tqdm
from concurrent.futures import ThreadPoolExecutor, as_completed# 读取 IP 地址
with open('hosts', 'r') as file:ip_addresses = [line.strip() for line in file.readlines()]# 初始化列表
non_alive_ips = []
ssh_password_success = []
ssh_key_success = []
ssh_failures = []# 检查 IP 存活状态
def is_alive(ip):# For Windowsresult = subprocess.run(['ping', '-n', '1', ip], stdout=subprocess.PIPE, stderr=subprocess.PIPE)return result.returncode == 0# 尝试使用密码进行 SSH 登录
def ssh_login_with_password(ip, username, password):try:client = SSHClient()client.set_missing_host_key_policy(AutoAddPolicy())client.connect(ip, username=username, password=password, timeout=5)client.close()return Trueexcept Exception as e:return False# 尝试使用 SSH 密钥进行登录
def ssh_login_with_key(ip, username, key_path):try:client = SSHClient()client.set_missing_host_key_policy(AutoAddPolicy())client.connect(ip, username=username, key_filename=key_path, timeout=5)client.close()return Trueexcept Exception as e:return False# 用户名和密码/密钥路径配置
USERNAME = 'root'
PASSWORD = 'xxxx.88'
KEY_PATH = r'E:\Code\Gitlab_Code\aliyun\kvm_centos\ssh_key'def check_ip(ip):if not is_alive(ip):return 'non_alive', ipelse:if ssh_login_with_password(ip, USERNAME, PASSWORD):return 'ssh_password_success', ipelif ssh_login_with_key(ip, USERNAME, KEY_PATH):return 'ssh_key_success', ipelse:return 'ssh_failures', ip# 检查每个 IP 地址
# 使用多线程检查 IP 地址
# 使用ThreadPoolExecutor来并发执行任务,最大工作线程数为10
with ThreadPoolExecutor(max_workers=10) as executor:# 提交检查每个IP地址的任务,并将任务对象与IP地址映射关系存储在字典futures中futures = {executor.submit(check_ip, ip): ip for ip in ip_addresses}# 遍历所有完成的任务,使用tqdm显示进度条for future in tqdm(as_completed(futures), total=len(ip_addresses), desc="Checking IPs"):# 获取任务执行结果和对应的IP地址result, ip = future.result()# 根据检查结果,将IP地址添加到相应的列表中if result == 'non_alive':non_alive_ips.append(ip)elif result == 'ssh_password_success':ssh_password_success.append(ip)elif result == 'ssh_key_success':ssh_key_success.append(ip)elif result == 'ssh_failures':ssh_failures.append(ip)# 输出结果
print("Non-alive IPs:", non_alive_ips)
print("SSH login with password successful:", ssh_password_success)
print("SSH login with key successful:", ssh_key_success)
print("Alive but SSH login failed:", ssh_failures)# 写入结果到文件
with open('output.txt', 'w') as output_file:output_file.write("[no_alive]\n")output_file.write("\n".join(non_alive_ips) + "\n")output_file.write("[password]\n")output_file.write("\n".join(ssh_password_success) + "\n")output_file.write("[key]\n")output_file.write("\n".join(ssh_key_success) + "\n")output_file.write("[fail]\n")output_file.write("\n".join(ssh_failures) + "\n")print("Results have been written to output.txt")

在这里插入图片描述
在这里插入图片描述

5、Ansbile实现步骤

1、上面生成的文件作为hosts使用

[fail]
192.168.84.37
192.168.84.38
192.168.99.160
192.168.99.176
192.168.99.254
192.168.102.200
192.168.102.248
192.168.102.249
192.168.102.250
192.168.102.251
#可以定义环境变量,方便登录使用
[fail:vars]
ansible_user=root
ansible_password="xxxxxx.88"
ansible_ssh_private_key_file=/opt/ansible/ssh_key

2、给密码登录的添加公钥

ansible password  -i ./all_host -m authorized_key -a "user={{ ansible_user }} state=present key='{{ lookup('file', '~/.ssh/id_rsa.pub') }}'" -u root --ask-pass

作用:这条命令会提示用户输入 SSH 密码,并将运行 Ansible 以 root 用户身份连接到 all_host 文件中列出的所有主机。然后,它会将当前用户的公钥添加到这些主机上指定用户的 authorized_keys 文件中,以实现无密码 SSH 登录。

  1. ansible password -i ./all_host

    • ansible:Ansible 命令的入口点。
    • password:这里应该是指 Ansible 的 inventory 文件中定义的模块名称
    • -i ./all_host:指定 Ansible inventory 文件的位置,这里是 ./all_host
  2. -m authorized_key

    • -m authorized_key:指定要使用的 Ansible 模块,这里是 authorized_key 模块,用于管理 ~/.ssh/authorized_keys 文件。
  3. -a "user={{ ansible_user }} state=present key='{{ lookup('file', '~/.ssh/id_rsa.pub') }}'"

    • -a:为指定的模块传递参数。

    • "user={{ ansible_user }} state=present key='{{ lookup('file', '~/.ssh/id_rsa.pub') }}'"

      • user={{ ansible_user }}:指定要在目标主机上操作的用户,这里使用了变量 {{ ansible_user }},这个变量通常在 Ansible 的配置文件或命令行中定义。
      • state=present:确保公钥存在,如果不存在就添加。
      • key='{{ lookup('file', '~/.ssh/id_rsa.pub') }}':从本地文件 ~/.ssh/id_rsa.pub 中读取公钥,并将其添加到目标主机的 authorized_keys 文件中。
  4. -u root

    • -u root:以 root 用户身份连接到目标主机。
  5. --ask-pass

    • --ask-pass:提示输入 SSH 密码。这在目标主机还没有配置无密码 SSH 登录时很有用。

6、自动化配置安全

hosts.allowhosts.deny 文件是 TCP Wrappers 的一部分,用于在 Unix 和 Linux 系统上控制对服务的访问。TCP Wrappers 提供了一种通过 IP 地址、主机名或域名限制或允许访问服务的机制。

hosts.allowhosts.deny 文件的作用

  • hosts.allow:定义允许哪些主机访问哪些服务。
  • hosts.deny:定义拒绝哪些主机访问哪些服务。

这两个文件通常位于 /etc 目录下。

格式

这两个文件的每一行包含一条访问控制规则,格式如下:

php复制代码<服务列表> : <客户端列表> [: <选项>]
  • 服务列表:要控制的服务名称,可以是单个服务名,也可以是多个服务名,以逗号分隔。
  • 客户端列表:允许或拒绝访问的客户端,可以是 IP 地址、主机名或域名,也可以是多个客户端,以逗号分隔。
  • 选项(可选):可以包含日志记录或执行命令等额外操作。

使用示例

假设你有一台服务器,想控制对 SSH 服务的访问。

hosts.allow

允许特定 IP 地址访问 SSH 服务:

sshd : 192.168.1.100

允许特定子网访问 SSH 服务:

sshd : 192.168.1.0/24

允许特定主机名访问 SSH 服务:

sshd : trustedhost.example.com
hosts.deny

拒绝所有其他主机访问 SSH 服务:

sshd : ALL

使用场景

  1. 安全控制:通过限制对某些关键服务(如 SSH、FTP、SMTP 等)的访问,可以增强系统的安全性。
  2. 访问管理:在多用户环境中,可以根据需求灵活控制哪些用户或主机能够访问特定服务。
  3. 日志记录:结合日志选项,可以记录访问尝试,以便审计和监控。

示例需求

  1. /etc/hosts.deny 中写入 sshd:ALL,拒绝所有主机的 SSH 访问。

  2. /etc/hosts.allow
    中允许特定 IP 地址段和单个 IP 地址的 SSH 访问:

    • sshd:192.168.0.0/16:allow
    • sshd:192.168.102.20:allow
  3. 如果文件有变动,则重启 sshd 服务。

Ansible 剧本
编写一个 Ansible 剧本来自动执行上述操作。以下是完整的 Ansible 剧本代码:configure_ssh_hosts.yml

---
- name: 配置 hosts.allow 和 hosts.denyhosts: testbecome: yes  # 使用sudo权限vars:hosts_deny_content: "sshd:ALL"hosts_allow_content: |sshd:192.168.0.0/16:allowsshd:192.168.102.20:allowtasks:- name: 更新 hosts.deny 文件lineinfile:path: /etc/hosts.denyline: "{{ hosts_deny_content }}"create: yesregister: hosts_deny_result- name: 更新 hosts.allow 文件copy:content: "{{ hosts_allow_content }}"dest: /etc/hosts.allowregister: hosts_allow_result- name: 如果配置发生变化则重启 sshd 服务systemd:name: sshdstate: restartedwhen: hosts_deny_result.changed or hosts_allow_result.changed- name: 确保 sshd 服务已启用并正在运行systemd:name: sshdstate: startedenabled: yes

使用方式

定义剧本名称和目标主机:

[root@ansible-yunwei ansible]# cat hosts 
[test]
192.168.102.20
192.168.102.30

[root@ansible-yunwei ansible]# ansible-playbook -i ./hosts configure_ssh_hosts.yml PLAY [配置 hosts.allow 和 hosts.deny] *******************************************************************************************************************************TASK [Gathering Facts] *******************************************************************************************************************************************
ok: [192.168.102.30]
ok: [192.168.102.20]TASK [更新 hosts.deny 文件] ******************************************************************************************************************************************
ok: [192.168.102.30]
ok: [192.168.102.20]TASK [更新 hosts.allow 文件] *****************************************************************************************************************************************
ok: [192.168.102.30]
ok: [192.168.102.20]TASK [如果配置发生变化则重启 sshd 服务] ***************************************************************************************************************************************
skipping: [192.168.102.20]
skipping: [192.168.102.30]TASK [确保 sshd 服务已启用并正在运行] ****************************************************************************************************************************************
ok: [192.168.102.30]
ok: [192.168.102.20]PLAY RECAP *******************************************************************************************************************************************************
192.168.102.20             : ok=4    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
192.168.102.30             : ok=4    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   

在这里插入图片描述
在这里插入图片描述

注意事项

  • hosts.allow 文件中的规则优先于 hosts.deny 中的规则。如果一个主机被 hosts.allow 允许,则不会被 hosts.deny 拒绝。
  • 确保规则的顺序和逻辑正确,以免意外拒绝合法访问或允许非法访问。
  • 这些文件适用于支持 TCP Wrappers 的服务,不适用于所有服务。

通过合理配置 hosts.allowhosts.deny 文件,可以有效控制服务访问,提高系统的安全性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/36475.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

World of Warcraft [CLASSIC] plugin lua

World of Warcraft [CLASSIC] plugin lua 魔兽世界lua脚本插件 World of Warcraft API - Wowpedia - Your wiki guide to the World of Warcraft D:\World of Warcraft\_classic_\Interface\AddOns zwf.lua function CountdownFunc()CountdownFrame CreateFrame("Fram…

仓库管理系统14--仓库设置

1、添加窗体 <UserControl x:Class"West.StoreMgr.View.StoreView"xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x"http://schemas.microsoft.com/winfx/2006/xaml"xmlns:mc"http://schemas.openxmlformats.…

k-NN 剪辑近邻法

本篇文章是博主在人工智能等领域学习时&#xff0c;用于个人学习、研究或者欣赏使用&#xff0c;并基于博主对人工智能等领域的一些理解而记录的学习摘录和笔记&#xff0c;若有不当和侵权之处&#xff0c;指出后将会立即改正&#xff0c;还望谅解。文章分类在AI学习笔记&#…

计算机缺失OpenCL.dll怎么办,OpenCL.dll丢失的多种解决方法

在使用电脑的过程中&#xff0c;我们经常会遇到一些开机弹窗问题。其中&#xff0c;开机弹窗找不到OpenCL.dll是一种常见的情况。本文将详细介绍开机弹窗找不到OpenCL.dll的原因分析、解决方法以及预防措辞&#xff0c;帮助大家更好地解决这一问题。 一&#xff0c;了解OpenCL.…

Swift开发——简单App设计

App的界面设计需要具有大量的图像并花费大量的时间,这样的应用不方便学习和交流,这里重点介绍SwiftUI界面元素的用法,通过简单App设计过程的讲解,展示图形用户界面应用程序的设计方法。 01、简单App设计 按照9.1节工程MyCh0901的创建方法,创建一个新的工程MyCh0902,此时工…

Yolov8可视化界面使用说明,含代码

⭐⭐ YOLOv8改进专栏|包含主干、模块、注意力机制、检测头等前沿创新 ​ ⭐⭐ YOLOv8可视化界面如下 使用需要安装opencv-python、torch、numpy及PySide6(python版本>3.9) pip install PySide6 pip install numpy pip install opencv-python 使用说明 运行下方代码&#xf…

上市公司银行专利申请数据集(2003-2022年)

数据简介&#xff1a;上市商业银行的专利申请数据是可作为金融科技创新水平的关键指标&#xff0c;这些数据反映了银行在金融技术领域的创新能力。发明专利因其创新性、技术深度和行业代表性&#xff0c;被赋予了特别的重视。遵循郭晔等人(2022)的研究方法&#xff0c;使用国家…

设置日历程序

目录 一 设计原型 二 后台源码 一 设计原型 二 后台源码 namespace 设置日历 {public partial class Form1 : Form{public Form1(){InitializeComponent();}private void dateTimePicker1_ValueChanged(object sender, EventArgs e){richTextBox1.Text dateTimePicker1.T…

【教程】安装DGL/PyG图神经网络编程环境

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhagn.cn] 如果本文帮助到了你&#xff0c;欢迎[点赞、收藏、关注]哦~ 关于cuda的安装&#xff0c;可以看这个&#xff1a; 【教程】保姆级安装NVIDIA CUDA、CUDNN环境全纪录解决SSH一段时间自动断开报Destination Host Un…

大数据------JavaWeb------MyBatis(完整知识点汇总)

MyBatis MyBatis简介 定义 它是一款优秀的持久层框架&#xff0c;用于简化JDBC开发它原来是Apache的一个开源项目iBatis&#xff0c;后来改名为MyBatis中文官网&#xff1a;https://mybatis.org/mybatis-3/zh_CN/index.html JaveEE三层架构 表现层&#xff08;做页面展示&…

Coldrage Dagger

剃刀高地【寒怒匕首 Coldrage Dagger】 2020.11.26.剃刀高地刷【寒怒匕首】-1_网络游戏热门视频 2020.11.26.剃刀高地刷【寒怒匕首】-2_网络游戏热门视频

台式机通过网线直连笔记本,台式机通过笔记本上网【解决台式机没有网络的问题】

一、总览 将笔记本电脑和台式机使用网线连接起来。在笔记本电脑上打开网络和共享中心&#xff0c;进入“更改适配器设置”选项&#xff0c;找到当前连接的网卡&#xff0c;右键点击选择“属性”。在网卡属性中&#xff0c;找到“共享”选项卡&#xff0c;勾选“允许其他网络用…

湖北大学2024年成人高考函授报名专升本法学专业介绍

湖北大学&#xff0c;这所承载着深厚文化底蕴和学术积淀的高等学府&#xff0c;始终致力于为广大有志之士提供多元化的学习机会。在时代的浪潮中&#xff0c;为了满足社会对于高层次法律人才的需求&#xff0c;湖北大学特别推出了成人高等继续教育项目&#xff0c;为广大在职人…

黄历工具网/万年历/财神方位/日历/佛历/道历/24节气/PHP网站源码

黄历工具网/万年历/财神方位/日历/佛历/道历/24节气/PHP网站源码 演示地址&#xff1a; https://hl.caohongji.com/ 手机端地址&#xff1a; https://mhl.caohongji.com/ 客服&#xff1a; kkmp326 源码说明&#xff1a; 1、系统内的黄历宜忌、农历、日历、佛历、道…

前端基础--Vue2

前端技术发展史(了解) 1.前端历史 1.1.静态网页 1990 html 1.2.异步刷新-操作dom 1995 javascript 1.3.动态网站 Asp/jsp&#xff08;java&#xff09;,php等&#xff0c;后台臃肿 1.4.Ajax成为主流 异步请求 1.5.Html5 被认为是互联网的核心技术之一。HTML产生于19…

Docker之jekins的安装

jekins官网地址&#xff1a;Jenkins Plugins &#xff08;https://plugins.jenkins.io/&#xff09; jekins 的docker 官方地址&#xff1a;https://hub.docker.com/r/jenkins/jenkins jekins 的docker 允许命令文档地址&#xff1a; docker/README.md at master jenkinsci…

学分制系统 WebService_PantoSchool SQL注入致RCE漏洞复现

0x01 产品简介 学分制系统由上海鹏达计算机系统开发有限公司研发,是基于对职业教育特点和需求的深入理解,结合教育部相关文件精神,并广泛吸纳专家、学者意见而开发的一款综合性管理系统。系统采用模块化的设计方法,方便学校根据自身教学改革特点、信息化建设进程情况选择、…

Kubernetes之Scheduler详解

本文尝试从Kubernetes Scheduler的功能介绍、交互逻辑、伪代码实现、最佳实践、自定义Scheduler举例及其历史演进6个方面进行详细阐述。希望对您有所帮助&#xff01; 一、Kubernetes Scheduler 功能 Kubernetes Scheduler 是 Kubernetes 集群的核心组件之一&#xff0c;负责…

Qwen2本地web Demo

Qwen2的web搭建(streamlit) 千问2前段时间发布了&#xff0c;个人觉得千问系列是我用过最好的中文开源大模型&#xff0c;所以这里基于streamlit进行一个千问2的web搭建&#xff0c;来进行模型的测试 一、硬件要求 该文档中使用的千问模型为7B-Instruct&#xff0c;需要5g以…

ROT5、ROT13、ROT18、ROT47全系列加解密小程序

ROT5、ROT13、ROT18、ROT47全系列加解密小程序 这几天在看CTF相关的课程&#xff0c;涉及到古典密码学和近代密码学还有现代密码学。自己编了一个关于ROT全系列的加、解密小程序。 ​ ROT5、ROT13、ROT18、ROT47 编码是一种简单的码元位置顺序替换暗码。此类编码具有可逆性&a…