目录
一、项目介绍
二、项目背景
1.互联网快速发展
2.云时代
3.项目准备
1.运维自动化难点和痛点
2.项目技术难点
3.项目功能演示
三.整体工程设计
1.资产的自动化扫描发现
2.Ansible的自动化任务执行
四、项目环境搭建
1.项目环境要求
2.项目目录的配置
五、远程服务器虚拟环境的配置
六、MySQL数据库配置
1.远程用户登录配置
2.Django数据库配置
七、第一个DevOPS工程
1.项目功能
2.项目开发步骤
3.项目开发(一) 信息采集接口的实现
4.项目开发(二) 信息获取接口的实现
5.Django项目日志管理
6.Django项目邮件告警管理
7.知识点拓展: Ipython
8.常用快捷操作
八、第二个DevOPS工程
1.Django工程多配置文件
2.Django工程应用与模块加载
3.数据库模型设计
4.资产管理的技术实现
5.资产管理探测流程
6.主机存活探测协议
7.主机存活探测模块和工具
8.Nmap的Python操作接口: python-nmap
9.SSH端口存活扫描
九、Python的SSH登录模块paramiko
一、项目介绍
本项目通过 KVM 虚拟化搭建 Linux 系统集群,使用 Ansible 实现 Linux 集群下的批量部署与自动化管理,实现Web 形式的自动化运维系统 , 集中批量控制服务器 , 最终实现能支撑 1000 台实例的环境提供管理和自动化任务, 提高运维工程师的工作质量和效率。 项目基于HTTP 实现自动化任务接受和响应接口设计,基于MySQL 用作的关系型数据存取, 基于 Redis 的任务锁机制和消息队列, 基于 MongoDB 的事件日志记录, 最终实现邮件通知功能、敏感数据加密功能、日志事件记录功能。
二、项目背景
1.互联网快速发展
- 网站用户规模、使用快速上升
- 要求庞大系统支撑能力
- 更加快速的运维效率应对突发流量
- 更加自动化的方式减少人工投入成本
- 更加可靠的技术手段,保障系统的稳定
2.云时代
- 腾讯云、阿里云、亚马逊云、青云等云厂商的市场份额不断增加
- 大部分技术架构设计不再以网络设计、IDC和系统硬件等方面作为重点
- 运维基础的、繁琐的工作逐步减少
- 小公司也不再需要一个运维工程师或者系统工程师
结论 : 在这样的时代背景下, 大型互联网公司为了应对市场的快速变化,就需要运维自动化。
3.项目准备
1.运维自动化难点和痛点
- 开发人员: 没有系统管理、网络管理等相关运维工作经验,项目设计往往是大打折扣的。
- 运维人员: 不具备开发能力、没有项目的开发经验或能力
- 做好一个优秀的运维开发人员DevOPS = 运维能力 + 开发能力
本次项目实战就是用最短的时间、手把手地完成运维开发系统的开发实战。
2.项目技术难点
- 基本技能
- DevOPS构建之路
- Python基础语法
- Django框架
- 自动化资产扫描发现
- 资产扫描的作用
- nmap的作用
- telnetlib端口扫描
- pexpect登录探测
- paramiko登录探测
- Docker容器扫描
- KVM虚拟机扫描
- snmp网络设备扫描
- SDK调用扫描ESXI资产信息
- Ansible自动化任务
- Ansible的安装与配置
- Python与Ansible的操作
- Ansible adhoc
- Ansible playbook
- 核心类调用
- API 接口的封装
- 方法的改写
- Redis消息存储
- Mongo事件日志
3.项目功能演示
- 资产自动化扫描
三.整体工程设计
1.资产的自动化扫描发现
用 Python 程序扫描发现企业内部的所有资产 ( 服务器资产 ) ,当资产出现变动时能自动及时的发现并完成资产变更(eg: 服务器 IP 变更、机器集体报废 ) 。
2.Ansible的自动化任务执行
用 Ansible 的 ad-hoc 和 playbook 实现批量主机的自动化任务。
四、项目环境搭建
1.项目环境要求
- Python解释器: 3.x
- Django框架: 2.x
- IDE编辑器工具Pycharm: 不限制
- 自动化运维工具Ansible: 2.x
- 关系型数据库MySQL/Mariadb: 5.5.x
- 高性能的key-value非关系型数据库 Redis 软件下载: 5.0.5
- 分布式文件存储数据库 MongoDB 软件下载: 4.2.4
- Git工具与Github代码仓库: 不限制
2.项目目录的配置
- 创建Django项目devops
- 连接并配置远程服务器
[Tools] -> [Deployment]
- 配置本地目录和远程服务器目录的映射(Mapping)
- 上述操作完成, 本地文件修改, 远程服务器文件也同时修改.
五、远程服务器虚拟环境的配置
- 连接远程服务器命令行bash
- 创建虚拟环境并激活虚拟环境
cd /data/www/devops
virtualenv -p /usr/bin/python3 env
source env/bin/active
pip install Django==2.2
- 出现的报错及处理方式
# sqlite版本问题
django.core.exceptions.ImproperlyConfigured: SQLite 3.8.3 or later is
required (found 3.7.17).
解决方式: 不使用sqlite存储数据, 使用mysql
# devops/settings.py
# 将sqlite数据库存储配置注释
# DATABASES = {
# 'default': {
# 'ENGINE': 'django.db.backends.sqlite3',
# 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
# }
# }
- 远程服务器解释器和目录映射的配置
- 在远程服务器上测试Django项目是否可以成功运行
python manage.py runserver
六、MySQL数据库配置
1.远程用户登录配置
- 管理数据库服务
systemctl start mariadb
systemctl enable mariadb
- 用户授权
- 测试用户授权是否成功
2.Django数据库配置
- 修改配置文件的信息
- 生成数据库表
- 测试数据表是否创建?数据信息是否写入?
连接 mariadb 数据库
配置数据库信息
访问数据库表和数据内容
到这了为止,关于数据库的配置结束。
DevOPS 工程快速入门和引导
- 运维模块: 了解运维的工作、Linux系统的基本操作、数据库基本管理操作、网络知识等。
- 开发模块: 本项目的重点, 掌握Python基础知识、常见数据类型、Django框架的技术模块、DevOPS项目构建模块等。
七、第一个DevOPS工程
1.项目功能
记录 HTTP 访问的 IP 及用户 UA 信息
2.项目开发步骤
- 创建Django工程
- 创建Django APP应用
$ python manage.py startapp scanhosts
- 文件配置settings
# settings.py
# 1). 将新建的APP加入到项目中
INSTALLED_APPS = [
......省略部分
'django.contrib.staticfiles',
'scanhosts',
]
# 2). 配置数据库: 使用mysql数据库,而不是默认的sqlite数据库。
# DATABASES = {
# 'default': {
# 'ENGINE': 'django.db.backends.sqlite3',
# 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
# }
# }
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'devopsProject', # 数据库名称
'USER': 'devops', # 用户名
'PASSWORD': 'westos', # 用户密码
'HOST': '127.0.0.1', # 数据库服务器所在主机名
'PORT': '3306', # 数据库端口
}
}
# 3). 语言和时区的设置(根据自己项目的需求, 选择修改)
# LANGUAGE_CODE = 'en-us'
# TIME_ZONE = 'UTC'
LANGUAGE_CODE = 'zh-hans' # 语言选择中文
TIME_ZONE = 'Asia/Shanghai' # 时区选择亚洲/上海
- 数据库模型建模models
安装数据库开发软件
$ yum install mariadb-devel -y
安装数据库连接模块 ( 必须先安装 mariadb-devel , 否则会报错 )
$ pip install mysqlclient
编辑数据库模型文件 :
# models.py
"""
- 一个类对应一个数据库表;
- 类的一个属性对应数据库表的一个表头;
- max_length: 字符串最大长度, 对应数据库的varchar类型
- default: 指定默认值
- verbose_name: 指定Django后台显示的列头信息
- auto_now: 每次修改记录时自动更新为当前时间
- Meta类的设置
- verbose_name: 指定Django后台显示的表名称单数
- verbose_name_plural: 指定Django后台显示的表名称复数
- db_table: 指定数据库表的名称, 默认是APP名称_类名称.
"""
class UserIPInfo(models.Model):
ip = models.CharField(max_length=150, default='', verbose_name='IP地址')
time = models.DateTimeField(verbose_name='更新时间', auto_now=True)
class Meta:
verbose_name = '用户访问地址信息表'
verbose_name_plural = verbose_name
db_table = 'user_IP_info'
class BrowseInfo(models.Model):
# null=True: 是针对数据库而言,True表示数据库的该字段可以为空。
user_agent = models.CharField(max_length=100, default='',
verbose_name='用户浏览器信息', null=True)
disk_id = models.CharField(max_length=256, default='', verbose_name='唯
一设备ID')
"""
ForeignKey是一种关联字段,将两张表进行关联的方式
on_delete: 是否级联删除, Django1.x默认级联删除, Django2.x必须手动指定
on_delete有CASCADE、PROTECT、SET_NULL、SET_DEFAULT、SET()五个可选择的值
CASCADE:此值设置,是级联删除。
PROTECT:此值设置,是会报完整性错误。
SET_NULL:此值设置,会把外键设置为null,前提是允许为null。
SET_DEFAULT:此值设置,会把设置为外键的默认值。
SET():此值设置,会调用外面的值,可以是一个函数。
"""
user_ip = models.ForeignKey('UserIPInfo', on_delete=models.DO_NOTHING)
class Meta:
verbose_name = '用户浏览器信息表'
verbose_name_plural = verbose_name
db_table = 'browse_info'
根据 ORM( 对象关系映射 ) 将面向对象形式的模型进行迁移, 生成中间代码
$ python manage.py makemigrations
# 代码执行效果, 生成迁移文件,所在位置: scanhosts/migrations
Migrations for 'scanhosts':
scanhosts/migrations/0001_initial.py
- Create model UserIPInf
将生成的迁移文件转成 SQL 语句并执行 SQL 语句, 创建对应的数据库及数据库表
$ python manage.py migrate
- Django后台管理界面
创建后台管理的超级用户
$ python manage.py createsuperuser
Username (leave blank to use 'kiosk'): admin
Email address: admin@qq.com
Password:
Bypass password validation and create user anyway? [y/N]: y
Superuser created successfully.
启动 Django 项目 , 默认开启的端口是 8000
$ python manage.py runserver
Django version 2.2.5, using settings 'first_devops.settings'
Starting development server at http://127.0.0.1:8000/
访问项目后台管理界面, 输入超级用户名称和密码即可进入后台界面.
- 项目工程设计
当用户发起 HTTP 请求时, Django 的采集接口将 HTTP 请求的头部信息 headers 里面的 IP 和 UA 信息采集, 并存储到数据库中。 当用户想要访问采集数据时, 从数据库中读取,以界面的方式展示给用户。
- 项目开发
3.项目开发(一) 信息采集接口的实现
- url设计
配置 URL , 当用户访问 http://127.0.0.1:8000/sendinfos 这个网址时, 将用户请求交给 user_info视图函数处理。
# first_devops/urls.py
urlpatterns = [
path('admin/', admin.site.urls),
url(r'^sendinfos/$', user_infos),
]
- 视图函数的实现
# scanhosts/views.py
def user_info(request):
# request.META 是一个Python字典,包含了所有本次HTTP请求的Header信息,比如用户IP
地址和用户Agent(通常是浏览器的名称和版本号)
ip = request.META.get('REMOTE_ADDR')
user_agent = request.META.get('HTTP_USER_AGENT')
# 使用filter()方法对数据进行过滤, 返回的是列表, 列表元素是符合条件的对象。
user_obj = UserIPInfo.objects.filter(ip=ip)
# 如果没有找到,则新建UserIPInfo对象,并获取对象编号(为了和BrowseInfo表关联)
if not user_obj:
res = UserIPInfo.objects.create(ip=ip)
user_ip_id = res.id
else:
user_ip_id = user_obj[0].id
# 新建BrowseInfo对象
BrowseInfo.objects.create(user_agent=user_agent, user_ip_id=user_ip_id)
# 字典封装返回的数据信息
result = {
'STATUS': 'success',
'INFO': 'User Info',
'IP': ip,
'User-Agent': user_agent
}
# 以json的方式封装返回, 下面的两种方式任选一种.
# return HttpResponse(json.dumps(result),
content_type='application/json')
return JsonResponse(result)
- 浏览器访问效果图
可以多试试其他浏览器访问, 看看是否返回不同的结果。
浏览器访问结束后, 访问 MySQL 数据库, 看是否将数据信息采集成功并通过 ORM 的方式写入数据库中。
4.项目开发(二) 信息获取接口的实现
- url设计
配置 URL, 当用户访问 http://127.0.0.1:8000/getinfos 这个网址时, 将用户请求交给 user_history视图函数处理。
# first_devops/urls.py
urlpatterns = [
path('admin/', admin.site.urls),
url(r'^sendinfos/$', user_info),
url(r'^getinfos/$', user_history),
]
- 视图函数的实现
# scanhosts/views.py
def user_history(request):
# 获取UserIPInfo表的所有对象信息;
ip_lists = UserIPInfo.objects.all()
infos = {}
# 获取每个IP访问网站浏览器的信息, 格式如下:
"""
infos = {
'127.0.0.1' : ['UA-1', 'ua-2'],
'172.25.254.1' : ['UA-1', 'ua-2'],
}
"""
for item in ip_lists:
infos[item.ip] = [b_obj.user_agent for b_obj in
BrowseInfo.objects.filter(user_ip_id=item.id)]
result = {
'STATUS': 'success',
'INFO': infos
}
return JsonResponse(result)
- 浏览器访问效果图
5.Django项目日志管理
- 在编写程序过程中,很难免的会出现一些问题,程序并非按照我们预想的那样运行,这个时候我们通常会对程序进行调试,来看看到底是哪边出了问题。而程序日志是来帮助我们记录程序运行过程的帮手,善用日志的程序员也就能很快找出自己程序的问题所在从而快速解决问题。
- 在服务器级别的组件中都有对应的日志文件,例如MySQL、Redis、nginx、uWSGI都会在运行过程中将一些信息写到日志文件中。
- Django使用python的内置模块logging来管理自己的日志, 包含四大组件: 日志记录器Loggers、日志处理器Handlers、日志过滤器Filters和日志格式化工具Formatters。
Django 项目日志管理详情查看官方文档 : https://docs.djangoproject.com/en/2.2/topics/logging/
- 配置日志的相关信息
# first_devops/settings.py
# 日志管理的配置
LOGGING = {
'version': 1,
# disable_existing_loggers是否禁用已经存在的logger实例。默认值是True.
'disable_existing_loggers': False,
# formatters: 定义输出的日志格式。
'formatters': {
'verbose': {
# 格式化属性查看资料:
https://docs.python.org/3/library/logging.html#logrecord-attributes
'format': '{levelname} {asctime} {module} : {lineno} {message}',
# 变量的风格
'style': '{',
# 日期显示格式
'datefmt': '%Y-%m-%d %H:%M:%S',
},
},
# handlers定义处理器。
'handlers': {
'file': {
# 日志处理级别
'level': 'INFO',
# 日志处理类, 详细的请查看网站:
https://docs.python.org/3/library/logging.handlers.html
'class': 'logging.FileHandler',
# 日志处理后输出格式
'formatter': 'verbose',
# 记录日志的文件名, 存储在当前项目目录下的devops.log文件
'filename': os.path.join(BASE_DIR, 'devops.log')
},
},
# loggers定义logger实例。
'loggers': {
'django': {
# 对应的handles对象列表
'handlers': ['file'],
# logger实例输出的日志级别
'level': 'INFO',
# 日志是否向上级传递。True 向上级传,False 不向上级传。
'propagate': True,
},
}
}
- 写入日志
修改视图函数的逻辑内容, 在合适的位置添加日志输出, 便于程序的测试与排错。
- 重新访问网页, 查看devops.log文件测试日志是否成功写入
6.Django项目邮件告警管理
在 web 应用中,服务器对客户发送邮件来通知用户一些信息,可以使用邮件来实现。 Django 中提供了邮件接口,使我们可以快捷的建设一个邮件发送系统。通常用于发送自定义消息或者通知告警等信息( 当然也可以通过短信接口或者微信接口, 便于维护人员快速响应) 。
- 服务器端开启smtp协议支持(此处以QQ邮件服务器为例服务器)
- 客户端配置settings文件
# first_devops/settings.py
# 邮件配置
EMAIL_HOST = 'smtp.qq.com'
EMAIL_HOST_USER = 'QQ邮箱'
EMAIL_HOST_PASSWORD = '登录授权码(注意: 不是登录密码)'
EMAIL_PORT = 465
EMAIL_SUBJECT_PREFIX = 'Python开发社区'
EMAIL_USE_SSL = True
- 在Django的交互式环境测试邮件是否发送成功
$ python manage.py shell
>>> from django.core.mail import send_mail
>>> help(send_mail)
>>> send_mail(subject="Django邮件发送测试代码", message='邮件发送测试成功',
from_email='发送人的邮箱地址', recipient_list=['接收人的邮箱地址1', '接收人的邮箱地
址2'])
1
- 查看邮箱是否收到测试邮件
发送邮件在很多业务场景都会适用, 为了方便操作, 将邮件发送的内容封装成一个工具, 减少开发过程中的重复操作, 提高效率。 操作如下:
- 将项目常用的功能封装到utils模块中, 创建的项目结构,如下:
- 编写封装类SendMail的类
# first_devops/scanhosts/utils/tools.py
import logging
from django.core.mail import send_mail
from datetime import datetime
from first_devops import settings
class SendMail(object):
"""发送邮件的封装类"""
def __init__(self, subject, message, recipient_list, ):
# 给每个邮件的标题加上当前时间, 时间格式为年月日_小时分钟秒_传入的邮件标题
subject_time = datetime.now().strftime('%Y%m%d_%H%M%S_')
self.recipient_list = recipient_list
self.subject = subject_time + subject
self.message = message
def send(self):
try:
send_mail(
subject=self.subject,
message=self.message,
from_email=settings.EMAIL_HOST_USER,
recipient_list=self.recipient_list,
fail_silently=False
)
return True
except Exception as e:
logging.error(str(e))
return False
- 在Django自带的交互式环境shell‘中进行测试
$ python manage.py shell
>>> from scanhosts.utils.tools import SendMail
>>> mail = SendMail('Django 测试标题', '邮件正文内容', ['976131979@qq.com'])
>>> mail.send()
True
- 测试效果:
7.知识点拓展: Ipython
- Ipython介绍
- 一个基于Python的交互式解释器
- 自动补全、历史记录、获得对象信息
- Ipython的安装
$ pip install ipython
- Ipython使用
$ ipython
Python 3.7.5 (default, Oct 25 2019, 15:51:11)
Type 'copyright', 'credits' or 'license' for more information
IPython 7.10.2 -- An enhanced Interactive Python. Type '?' for help.
In [1]:
常用快捷操作
八、第二个DevOPS工程
实现 devops 工程之前, 使用 Pycharm 编辑器工具创建 devops 项目。
1.Django工程多配置文件
- base.py文件: 基本的配置文件,将原先seetings.py文件的内容拷贝进来.(参考第一个devops项目)
- 配置数据库
- 配置时区和语言
- development.py文件: 开发环境的配置文件
from .base import *
DEBUG = True
- production.py文件: 生产环境的配置文件
from .base import *
# 开发环境一定要关闭调试模式
DEBUG = False
# 允许所有主机访问
ALLOWED_HOSTS = ['*']
- 修改manage.py文件, 默认寻找的设置文件是当前项目中的settings文件, 如果是开发环境, 修改如下:
def main():
os.environ.setdefault('DJANGO_SETTINGS_MODULE',
'devops.settings.development')
# ......此处省略代码
if __name__ == '__main__':
main()
如果项目将来需要上线, 修改启动项目访问的配置文件为生产环境的配置文件即可, 如下 :
def main():
os.environ.setdefault('DJANGO_SETTINGS_MODULE',
'devops.settings.production')
# ......此处省略代码
if __name__ == '__main__':
main()
- 启动项目
$ python manage.py runserver
Django version 2.2.5, using settings 'devops.settings.development'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
2.Django工程应用与模块加载
为了方便在一个大的 Django 项目中,管理实现不同的业务功能, 我们会在项目中创建多个 APP 实现功能。为了更加方便管理APP , 项目结构更加清晰。可以专门创建 apps 目录存储项目应用, 专门创建extra_apps存储项目第三方 APP , 项目结构如下所示 :
但项目运行时, 不会自动寻找 apps 和 extra_apps 子目录中创建的 APP , 需要手动在配置文件中配置,修改devops/settings/base.py 文件, 添加内容如下 :
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# 将apps目录和extra_apps添加到python的搜索模块的路径集中
sys.path.insert(0, os.path.join(BASE_DIR, 'apps'))
sys.path.insert(0, os.path.join(BASE_DIR, 'extra_apps'))
# .........
添加成功后, 进入 Django 工程的交互式环境, 查看 sys.path 变量的值, 判断是否添加成功 ?
$ python manage.py shell
In [1]: import sys
In [2]: sys.path
Out[2]:
['/home/kiosk/PycharmProjects/devops/devops/extra_apps',
'/home/kiosk/PycharmProjects/devops/devops/apps',
'/home/kiosk/PycharmProjects/devops',
# .......此处为了美观, 省略部分路径........
]
3.数据库模型设计
资产管理
为什优先实现资产管理 ?
- 资产管理是运维的基本工作;
- 资产管理是DevOPS系统的基础;资产管理是自动化运维平台构建的基础。
4.资产管理的技术实现
- 资产信息的手工录入: 手工操作工作量大,尤其是首次录入。
- 客户端主机主动上报: 需要给不同的设备编写对应的客户端程序, 开发工作量大。
- 服务器端主动发现探测:
抽象与约定 :
- 内网Linux服务器主机类型(Centos4-6、Ubuntu12、14+)
- 系统内部开通ssh服务端口为Linux服务器
- Linux系统开放ssh的端口范围(22、20022、202)
- 安全规则(开放允许探测协议和登录的限制)
- 网络设备开通snmp服务,且community都已经统一
- 虚拟机不再运行容器等虚拟资产
- 网络设备(cisco系列等)
5.资产管理探测流程
- 存活探测: 获取局域网内存活的IP列表
- 主机探测: 获取系统版本(SN、版本、MAC地址)
- 主机关系探测: 识别宿主主机和虚拟机的关系
- 网络设备的探测: 探测网络设备信息(SN、设备名等),使用snmp协议
- 其他设备的探测:
6.主机存活探测协议
- ICMP(Internet Control Message Protocol)Internet控制报文协议。它是TCP/IP协议簇的一个子协议,用于在IP主机、路由器之间传递控制消息。控制消息是指网络通不通、主机是否可达、路由是否可用等网络本身的消息。这些控制消息虽然并不传输用户数据,但是对于用户数据的传递起着重要的作用。
- 传输控制协议(TCP,Transmission Control Protocol)是一种面向连接的、可靠的、基于字节流的传输层通信协议。
7.主机存活探测模块和工具
Nmap 探测工具
Nmap ,也就是 Network Mapper ,最早是 Linux 下的网络扫描和 嗅探 工具包。是一款用于网络发现和安全审计的网络安全工具。
- 主机发现 - 识别网络上的主机。例如,列出响应TCP和/或ICMP请求或打开特定端口的主机。
# 使用-sP开关(Arp ping)执行PING命令,与windows / linux ping命令类似。
$ ping -c1 -w1 172.25.254.197
$ nmap -n -sP 172.25.254.197
$ nmap -n -sP 172.25.254.0/24
- 端口扫描 - 枚举目标主机上的开放端口。
# Nmap默认端口的扫描范围1-10000
$ nmap -n -p 172.25.254.197
# 具体指定要扫描的端口为50-80
$ nmap -n -p50-80 172.25.254.197
# 具体指定要扫描的端口为22和80
$ nmap -n -p22,80 172.25.254.197
- 版本检测 - 询问远程设备上的网络服务以确定应用程序名称和版本号。
- OS检测 - 确定网络设备的操作系统和硬件特性。
# -O是检测操作系统交换机
$ nmap -O 172.25.254.197
可与脚本进行脚本交互 - 使用 Nmap 脚本引擎( NSE )和 Lua 编程语言。
查看 172.25.254.197 这台 主机是否开启?
查看 172.25.254.0/24 局域网内存活的主机信息及存活主机个数。
8.Nmap的Python操作接口: python-nmap
python-nmap 是一个使用 nmap 进行端口扫描的 python 库,它可以很轻易的生成 nmap 扫描报告,并且可以帮助系统管理员进行自动化扫描任务和生成报告。同时,它也支持nmap 脚本输出。
# 安装nmap的第三方模块
$ pip install python-nmap
具体的代码调用如下:
import nmap
# 实例化对象, portScanner()类用于实现对指定主机进行端口扫描
nm = nmap.PortScanner()
# 以指定方式扫描指定主机或网段的指定端口
result = nm.scan(hosts='172.25.254.0/24', arguments='-n -sP')
print("扫描结果: ", result)
# 返回的扫描具体的nmap命令行
print("nmap命令行: ", nm.command_line())
# 返回nmap扫描的主机清单,格式为列表类型
print("主机清单: ", nm.all_hosts())
# 查看指定主机信息
print('172.25.254.197的主机信息: ', nm['172.25.254.197'])
代码执行效果如下图所示 :
扫描结果:
{'nmap': {'command_line': 'nmap -oX - -n -sP 172.25.254.0/24', 'scaninfo': {},
'scanstats': {'timestr': 'Wed Dec 25 16:14:47 2019', 'elapsed': '6.06',
'uphosts': '2', 'downhosts': '254', 'totalhosts': '256'}}, 'scan':
{'172.25.254.197': {'hostnames': [{'name': '', 'type': ''}], 'addresses':
{'ipv4': '172.25.254.197'}, 'vendor': {}, 'status': {'state': 'up', 'reason':
'syn-ack'}}, '172.25.254.250': {'hostnames': [{'name': '', 'type': ''}],
'addresses': {'ipv4': '172.25.254.250'}, 'vendor': {}, 'status': {'state': 'up',
'reason': 'syn-ack'}}}}
nmap命令行: nmap -oX - -n -sP 172.25.254.0/24
主机清单: ['172.25.254.197', '172.25.254.250']
172.25.254.197的主机信息:
{'hostnames': [{'name': '', 'type': ''}], 'addresses': {'ipv4':
'172.25.254.197'}, 'vendor': {}, 'status': {'state': 'up', 'reason': 'syn-ack'}}
9.SSH端口存活扫描
- 使用telnet命令探测主机列表是否属于Linux服务器。
- telnet命令探测
$ telnet 172.25.254.197 22
- telnetlib模块探测
telnetlib模块提供的Telnet类实现了Telnet协议。
import telnetlib
import re
# 实例化对象
tn = telnetlib.Telnet(host='172.25.254.197', port=22, timeout=5)
# read_until读取直到遇到了换行符或超时秒数。默认返回bytes类型,通过decode方法解码为字符
串。
tn_result = tn.read_until(b"\n", timeout=5).decode('utf-8')
# 通过正则匹配且忽略大小写, 寻找是否ssh服务开启。
ssh_result = re.search(pattern=r'ssh', string=tn_result, flags=re.I)
# 如果能匹配到内容, 说明ssh服务开启, 是Linux服务器.
if ssh_result:
print("Linux服务器存活")
else:
print("其他服务器存活")
代码执行结果如下 :
Linux服务器存活
扫描探测小结
主机登录探测
什么是主机登录探测 ?
用一系列的验证方式循环进行 SSH 登录, 得到争取的登录方式。
主机 SSH 登录验证方式
SSH 常用来远程登录到远程机器,有两种常用的方法:
- 第一种便是账号密码登录。
- 第二种就是公钥私钥无密码登录。(如何实现无密码登录?)
Python 的 SSH 登录模块 pexpect
Pexpect 用来实现与 ssh 、 ftp 、 telnet 等程序的自动交互。 是 Expect 语言的一个 Python 实现,是
一个用来启动子程序,并使用正则表达式对程序输出做出特定响应,以此实现与其自动交互的 Python模块。
pexpect 的核心类和函数。
- 直接进程运行run()函数, 返回结果和状态。
import pexpect
cmd_result, exitstatus = pexpect.run('hostname', withexitstatus=True)
print("命令执行结果: ", cmd_result.decode('utf-8'))
print("命令执行的状态码: ", exitstatus)
执行结果如下:
命令执行结果: foundation0.ilt.example.com
命令执行的状态码: 0
- 启动子进程运行spawn()函数, 读取缓冲区数据
- 如果正则匹配成功
- 发送指令(send、sendline、sendcontrol)
- 退出当前会话, 进入终端交互式命令行
- 如果正则匹配不成功, 等待超时(TIMEOUT)或者子进程退出(pexpect.EOF)。
- 正则不管是否匹配成功, 都可以打印输出匹配的缓冲区结果(before和after)
pexpect 模块的缺陷 :
- 依赖终端命令的方式
- 不同的ssh登陆环境兼容性差
pexpect 项目实战 : ssh 仿真 SSH 登陆远程设备
下面的代码通过子进程运行 spawn 函数的方式实现了 SSH 客户端登陆的两种方式 :
- login_ssh_passwd函数是密码登录的封装。
- login_ssh_key函数是密钥登陆的封装。
import pexpect
# logging:专门做日志记录或者处理的模块。
import logging
# 日志的基本配置
# 官方符网站基本配置及使用: https://docs.python.org/zh-
cn/3/howto/logging.html#logging-basic-tutorial
logging.basicConfig(
level=logging.DEBUG, # 控制台打印的日志级别
filename='message.log', # 日志文件位置
filemode='a', # 写入文件的模式,a是追加模式,默认是追加模式
# 日志格式
format='%(asctime)s - %(pathname)s[line:%(lineno)d] - %(levelname)s: %
(message)s'
)
class SSH(object):
def login_ssh_passwd(self, hostname, username, password, port=22):
"""
用于pexpect实现ssh自动化用户密码登录
"""
print("ssh -p%s %s@%s" % (port, username, hostname))
if port and username and password:
ssh = pexpect.spawn("ssh -p%s %s@%s" % (port, username, hostname))
status_code = ssh.expect(['password', 'continue connecting
(yes/no)?'], timeout=5)
if status_code == 0:
ssh.sendline(password)
elif status_code == 1:
ssh.sendline('yes\n')
ssh.expect('password: ')
ssh.sendline(password)
index = ssh.expect(["#", pexpect.EOF, pexpect.TIMEOUT])
if index == 0:
print("logging in as root!")
logging.info("logging in as root!")
ssh.interact()
elif index == 1:
print("logging process exit!")
logging.error("logging process exit!")
elif index == 2:
print("logging timeout exit!")
logging.error("logging timeout exit!")
else:
print("Parameter error!")
logging.error("Paramiko error!")
def login_ssh_key(self, hostname, keyfile, username, port=22):
"""
用于实现pexpect实现ssh的自动化密钥管理
"""
print("ssh -i %s -p%s %s@%s" % (keyfile, port, username, hostname))
if hostname and keyfile and username and port:
ssh = pexpect.spawn("ssh -i %s -p%s %s@%s" % (keyfile, port,
username, hostname))
status_code = ssh.expect([pexpect.TIMEOUT, 'continue connecting
(yes/no)?'], timeout=5)
if status_code == 1:
ssh.sendline('yes\n')
index = ssh.expect(["#", pexpect.EOF, pexpect.TIMEOUT])
if index == 0:
print("logging in as root!")
logging.info("logging in as root!")
# 进入交互式环境
ssh.interact()
elif index == 1:
print("logging process exit!")
logging.error("logging process exit!")
elif index == 2:
print("logging timeout exit!")
logging.error("logging timeout exit!")
else:
print("Paramiko error!")
logging.error("Parameter error!")
def main():
sshClient = SSH()
# sshClient.login_ssh_passwd('172.25.254.197', 'root', 'redhat')
# 必须做过无密码连接
sshClient.login_ssh_key('172.25.254.197','/root/.ssh/id_rsa', 'root', )
if __name__ == '__main__':
main()
项目执行效果如下 :
Python的SSH登录模块paramiko
- 什么是paramiko?
paramiko 是一个用于做远程控制的模块 ,使用该模块可以对远程服务器进行命令或文件操作,paramiko 是用 python 语言写的一个模块,遵循 SSH2 协议,支持以加密和认证的方式,进行远程服务器的连接。
- 如何安装paramiko?
# 使用豆瓣的镜像源, 安装paramiko模块并指定安装版本为2.6.0.
$ pip install -i https://pypi.douban.com/simple paramiko==2.6.0
- paramiko核心组件
paramiko 包含两个核心组件: SSHClient 和 SFTPClient 。
- SSHClient的作用类似于Linux的ssh命令,是对SSH会话的封装,该类封装了传输(Transport),通道(Channel)及SFTPClient建立的方法(open_sftp),通常用于执行远程命令。
- SFTPClient的作用类似与Linux的sftp命令,是对SFTP客户端的封装,用以实现远程文件操作,如文件上传、下载、修改文件权限等操作。
- 项目代码: 基于paramiko实现ssh客户端密码远程登录
import paramiko
def login_ssh_passwd(hostname='172.25.254.197', port=22,
username='root', password='westos', command='df -h'):
"""
基于paramiko实现ssh自动化用户密码登录
:return:
"""
# 实例化SSHClient
with paramiko.SSHClient() as client:
# 自动添加策略,保存服务器的主机名和密钥信息,如果不添加,那么不再本地know_hosts文件中记录的主机将无法连接
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# 连接SSH服务端,以用户名和密码进行认证
client.connect(hostname=hostname, port=port, username=username,
password=password)
# 打开一个Channel并执行命令。 stdout 为正确输出,stderr为错误输出,同时是有1
个变量有值
stdin, stdout, stderr = client.exec_command(command)
# 打印执行结果
print(stdout.read().decode('utf-8'))
if __name__ == '__main__':
login_ssh_passwd(hostname='127.0.0.1', command='hostname')
运行效果如下 :
foundation0.ilt.example.com
- 项目代码: 基于paramiko实现ssh客户端密钥远程登录
def login_ssh_key( hostname='172.25.254.197', keyfile='./id_rsa',
username='root', port=22, command='df -h'):
"""
基于paramiko实现ssh的自动化密钥管理
"""
# 配置私人密钥文件位置
private = paramiko.RSAKey.from_private_key_file(keyfile)
# 实例化SSHClient
with paramiko.SSHClient() as client:
# 自动添加策略,保存服务器的主机名和密钥信息,如果不添加,那么不再本地
know_hosts文件中记录的主机将无法连接
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# 连接SSH服务端,以用户名和密码进行认证
client.connect(hostname=hostname, port=port, username=username,
pkey=private)
# 打开一个Channel并执行命令。 stdout 为正确输出,stderr为错误输出,同时是有1
个变量有值
stdin, stdout, stderr = client.exec_command(command)
# 打印执行结果
print(stdout.read().decode('utf-8'))
if __name__ == '__main__':
# login_ssh_passwd(hostname='127.0.0.1', command='hostname')
login_ssh_key(hostname='127.0.0.1', command='hostname')
运行效果如下:
foundation0.ilt.example.com
- SFTPClient实战代码: 上传和下载文件
SFTPCLient 作为一个 sftp 的客户端对象,根据 ssh 传输协议的 sftp 会话,实现远程文件操作,如上传、下载、权限、状态。
from_transport(cls,t) 创建一个已连通的SFTP
客户端通道
put(localpath, remotepath, callback=None, confirm=True) 将本地文件上传到服务
器 参数confirm: 是否调用stat()方法检查文件状态,返
回ls -l的结果
get(remotepath, localpath, callback=None) 从服务器下载文件到本
地
mkdir() 在服务器上创建目录
remove() 在服务器上删除目录
rename() 在服务器上重命名目录
stat() 查看服务器文件状态
listdir() 列出服务器目录下的文件
具体的实例代码如下 :
import paramiko
# 获取Transport实例
with paramiko.Transport(('172.25.254.197', 22)) as tran:
# 连接SSH服务端,使用password
tran.connect(username="root", password='westos')
# # 或使用
# # 配置私人密钥文件位置
# private = paramiko.RSAKey.from_private_key_file('./id_rsa')
# # 连接SSH服务端,使用pkey指定私钥
# tran.connect(username="root", pkey=private)
# 获取SFTP实例
sftp = paramiko.SFTPClient.from_transport(tran)
# 设置上传的本地/远程文件路径
localpath = "/etc/passwd"
remotepath = "/mnt/passwd"
# 执行上传动作
sftp.put(localpath, remotepath)
# # 执行下载动作
# sftp.get(remotepath, localpath)
- paramiko的应用和缺陷
系统信息获取
- 通过系统获取哪些信息
- 为什么要获取这些信息
- 有利于识别资产设备
- 是资产的基本信息, 是自动化平台的基础(实现自动化任务执行、定时任务、自动化报表、监控等相关功能)
- 此处只能实现主机类型信息的探测, 而不是Docker容器的探测
- 获取信息的Linux命令介绍
- 获取主机名的命令(选择通用方式): hostname、uname -a、cat /etc/sysconfifig/network(主要针对Centos)
- 获取系统版本: cat /etc/issue(可能为空)、cat /etc/redhat-release、uname、lsb_release
- 获取MAC地址: cat /sys/class/net/ [^vtlsb] */address、ifconfifig ens33
- 获取服务器硬件机型: dmidecode -s system-manufacturer、dmidecode -s systemproduct-name