def decrypt_file(self, filename): ''' 解密文件 :parm filename:需要解密的文件 ''' content = read_file(filename) if content[0]: ciphertext = content[1] else: self.logger.error('解密文件' + filename + '失败,在读取文件过程中出错,原因:' + content[1]) return (False, "解密文件失败,在读取文件过程中出错," + content[1]) plaintext = self.decrypt(ciphertext) if not plaintext[0]: self.logger.error('解密文件' + filename + '失败,在解密过程中出错,原因:' + plaintext[1]) return (False, "解密文件失败,在解密过程中出错," + plaintext[1]) result = self._write_file(filename, plaintext[1]) if not result[0]: self.logger.error('解密文件' + filename + '失败,在解密后回写文件过程中出错,原因:' + result[1]) return (False, "解密文件失败,在解密后回写文件过程中出错," + result[1]) else: self.logger.info('解密文件' + filename + '成功') return (True, "解密文件成功")
def _get_vault_pwd(self): ''' 获取vault密码,并初始化vault密码 ''' vault_pwd_file = self.options_dict.get('vault_password_file', False) ask_vault_pass = self.options_dict.get('ask_vault_pass', False) if ask_vault_pass: vault_password = ask_vault_pass else: if vault_pwd_file: this_path = os.path.realpath( os.path.expanduser(vault_pwd_file)) if os.path.exists(this_path): mode = self.loader.is_executable(this_path) result = read_file(this_path, mode=mode, sprfmt=b'\r\n', outfmt='bytes') if result[0]: vault_password = result[1] else: vault_password = None else: vault_password = None else: vault_password = None if vault_password: b_vault_password = string2bytes(vault_password) self.loader.set_vault_password(b_vault_password) self.vault_password = vault_password else: self.vault_password = None
def encrypt_file(self, filename): ''' 加密文件 :parm filename:需要加密的文件 ''' content = read_file(filename) if content[0]: plaintext = content[1] else: self.logger.error('加密文件' + filename + '失败,在读取文件过程中出错,原因:' + content[1]) return (False, "加密文件失败,在读取文件过程中出错," + content[1]) ciphertext = self.encrypt(plaintext) if not ciphertext[0]: self.logger.error('加密文件' + filename + '失败,在加密过程中出错,原因:' + ciphertext[1]) return (False, "加密文件失败,在加密过程中出错," + ciphertext[1]) else: ciphertext = ciphertext[1] result = self._write_file(filename, ciphertext) if not result[0]: self.logger.error('加密文件' + filename + '失败,在加密后回写文件过程中出错,原因:' + result[1]) return (False, "加密文件失败,在加密后回写文件过程中出错," + result[1]) else: self.logger.info('加密文件' + filename + '成功') return (True, "加密文件成功")
def yaml_loader(data, data_type='data'): ''' 解析yaml,把yaml文件或者字符串解析成为yaml列表格式 :参数 data:yaml文件或任意类型数据 data_type:数据类型,目前只能接受file或者data,默认为data :返回 元组:(bool, 列表或者错误信息) ''' if data_type not in ('file', 'data'): return (False, 'data_type参数不正确,只能为file或者data') if data_type == 'file': result = read_file(data) if result[0]: data = result[1] else: return result try: yaml_data = yaml.load(data) return (True, yaml_data) except Exception as e: try: reuslt = yaml.dump(data) if reuslt: return (True, data) else: return (False, '不能被yaml加载,原因:' + str(e)) except Exception as e: return (False, '不能被yaml加载,原因:' + str(e))
def yaml_loader(self, data, data_type='file'): ''' 将文件或者原始数据解析成yaml数据,如果是vault数据,将在这里解密 :parm data:路径或者原始数据 data_type:指定类型,文件或者原始数据 ''' if data_type == 'file' : log_prefix = '将yaml文件' + data + '的内容(必须为原始数据)解析为yaml格式的数据,' result = check_fileaccessible(data) if result[0] : filename = result[1] else : self.logger.error(log_prefix + '读取文件时失败,原因:' + result[1]) return (False, '读取文件时失败,' + result[1]) result = read_file(filename) if result[0] : content = result[1] else : self.logger.error(log_prefix + '读取文件时失败,原因:' + result[1]) return (False, '读取文件时失败,' + result[1]) else : log_prefix = '将原始yaml数据解析为yaml格式的数据,' content = data filename = '' # 是否写入文件中 result = yaml_loader(content, data_type='data') if result[0] : yaml_data = result[1] else : self.logger.error(log_prefix + '解析失败,原因:' + result[1]) return (False, '解析成yaml失败,' + result[1]) if not isinstance(yaml_data, (dict, list, tuple)) : self.logger.error(log_prefix + '解析失败,原因:该文件内容不是ansible支持的yaml数据') return (False, '解析成yaml失败,该文件内容不是ansible支持的yaml数据') self.logger.info(log_prefix + '解析成功') return (True, filename, content, yaml_data)
def _ansible_vault_encrpyt(self, data): ''' while True : vault_tempfile = tempdir + '/vault' + random_str(ranlen=20) + '_' + str(int(time.time())) result = write_file(vault_tempfile, 'w', data) if result[0] : break ''' result = write_random_file(data) if not result[0]: return result vault_tempfile = result[1] ansible_vault = VaultEditor(self.password) ansible_vault.decrypt_file(vault_tempfile) result = read_file(vault_tempfile) os.remove(vault_tempfile) return result
def rekey_file(self, filename, new_password): ''' 更改加密文件的valut密码 :parm new_password:新密码 filename:需要更换的文件 ''' if not new_password or new_password is None: self.logger.error('更改加密文件' + filename + '的valut密码失败,原因:新密码为空') return (False, "更改加密文件的valut密码失败,新密码为空") content = read_file(filename) if content[0]: ciphertext = content[1] else: self.logger.error('更改加密文件' + filename + '的valut密码失败,在读取文件过程中出错,原因:' + content[1]) return (False, "更改加密文件失败,在读取文件过程中出错," + content[1]) new_ciphertext = self.rekey(ciphertext, new_password) if not new_ciphertext[0]: self.logger.error('更改加密文件' + filename + '的valut密码失败,在加密过程中出错,原因:' + str(new_ciphertext[1])) return (False, '更改加密文件的valut密码失败,在加密过程中出错,' + str(new_ciphertext[1])) else: new_ciphertext = new_ciphertext[1] result = self._write_file(filename, new_ciphertext) if not result[0]: self.logger.error('更改加密文件' + filename + '的valut密码失败,在写入文件过程中出错,原因:' + result[1]) return (False, "更改加密文件的valut密码失败,在写入文件过程中出错," + result[1]) else: self.logger.info('更改加密文件' + filename + '的valut密码成功') return (True, "更改加密文件的valut密码成功")
def decrypt_file2text(self, filename): ''' 解密文件的内容,成功后直接输出 :parm filename:需要解密的文件 ''' content = read_file(filename) if content[0]: ciphertext = content[1] else: self.logger.error('解密文件' + filename + '的内容(成功后直接输出)失败,在读取文件过程中出错,原因:' + content[1]) return (False, "解密文件的内容(成功后直接输出)失败,在读取文件过程中出错," + content[1]) plaintext = self.decrypt(ciphertext) if not plaintext[0]: self.logger.error('解密文件' + filename + '的内容(成功后直接输出)失败,在解密过程中出错,原因:' + ciphertext[1]) return (False, "解密文件的内容(成功后直接输出)失败,在解密过程中出错," + plaintext[1]) else: self.logger.info('解密文件' + filename + ' 的内容(成功后直接输出)成功') return (True, "解密文件的内容(成功后直接输出)成功")
def encrypt_file2text(self, filename): ''' 加密文件的内容,成功后直接输出 :parm filename:需要加密的文件 ''' content = read_file(filename) if content[0]: plaintext = content[1] else: self.logger.error('加密文件' + filename + '的内容(成功后直接输出)失败,在读取文件过程中出错,原因:' + content[1]) return (False, "加密文件的内容(成功后直接输出)失败,在读取文件过程中出错," + content[1]) ciphertext = self.encrypt(plaintext) if not ciphertext[0]: self.logger.error('加密文件' + filename + '的内容(成功后直接输出)失败,在加密过程中出错,原因:' + ciphertext[1]) return (False, "加密文件的内容(成功后直接输出)失败,在加密过程中出错," + ciphertext[1]) else: self.logger.info('加密文件' + filename + ' 的内容(成功后直接输出)成功') return (True, "加密文件的内容(成功后直接输出)成功")
def roles(self, roles_path, this_basedir=None, preserve=True, together=False, name='', describe=''): ''' 检测单个roles的语法等是否正确 :参数 this_basedir:引用该roles的main文件的上级目录,例如/opt/devops/example/ansible/roles/nginx/main.yaml引用一个roles,那么该值为/opt/devops/example/ansible/roles/nginx/ roles_path:引用该roles的main文件写的roles路径 preserve:是否写入数据库 together:是否返回该roles下所有文件内容 name:yaml文件内容写入数据的名称 describe:yaml文件内容写入数据的描述 zhname:yaml文件内容写入数据的中文名称,很简短说明 :return 元组,第一个为执行结果, 成功为true,返回内容为(True,roles下所有文件内容(格式为字典,可能为空), roles下所有文件中include文件内容(格式为字典,可能为空)) 失败为False,返回失败原因 ''' content_dict = {} if preserve and together: sub_preserve = False else: sub_preserve = preserve if not name: name = roles_path result = self._isrolesname(name) if not result: self.logger.error('检测yaml文件roles名为' + roles_path + '失败,roles名不符合本系统要求的,注:虽然原生ansible支持这样写') return (False, '语法错误,roles名不符合本系统要求的,注:虽然原生ansible支持这样写') else: if this_basedir is None or not this_basedir: this_roles_path = roles_path else: try: this_roles_path = this_basedir + '/roles/' + roles_path except: this_roles_path = roles_path include_content = {} for this_dir in ('tasks', 'vars', 'handlers', 'meta', 'defaults'): yaml_file = this_roles_path + '/' + this_dir + '/main.yaml' result = read_file(yaml_file) if not result[0]: if this_dir == 'tasks': self.logger.error('检测yaml文件roles名为' + roles_path + '失败,' + this_dir + '/main.yaml不存在') return (False, this_dir + '/main.yaml不存在') continue else: content_dict[this_dir] = result[1] temp_dir = this_roles_path + '/templates/' content_dict['templates'] = {} result = get_pathlist(temp_dir, get_death=0, max_size=4 * 1024 * 1024) if result[0]: temp_list = result[1] for temp in temp_list: result = read_file(temp) if result[0]: temp_file = os.path.basename(temp) content_dict['templates'][temp_file] = result[1] if not content_dict['templates']: del content_dict['templates'] result = self.check_roles(content_dict) if result[0]: includefile_dict = result[1] for file, file_type in includefile_dict.items(): result = self.include(file, this_basedir=this_basedir, file_type=file_type, preserve=sub_preserve) if not result[0]: self.logger.error('检测yaml文件roles名为' + roles_path + '失败,roles包含的include文件' + file + '未通过语法检测,原因:' + result[1]) return (False, 'roles包含的include文件' + file + '未通过语法检测,' + result[1]) else: include_content.update({file: result[1]}) else: self.logger.error('检测yaml文件roles名为' + roles_path + '失败,' + this_dir + '/main.yaml语法错误,原因:' + result[1]) return (False, this_dir + '/main.yaml语法错误,' + result[1]) data = { 'main': {}, 'include': include_content, 'roles': { name: content_dict }, } if preserve: result = self.write2db(name, data, 'roles', describe=describe) if not result[0]: self.logger.error('检测yaml文件roles名为' + roles_path + '失败,无法写入数据库,' + result[1]) return (False, '无法写入数据库,' + result[1]) self.logger.info('检测yaml文件roles名为' + roles_path + '成功') if together: return (True, content_dict, include_content) else: return (True, {}, {})
def _handle_ciphertext(self, data=None, filename=None): ''' 对加密数据/文件内容的头部进行判断使用哪种方式加密 data或者filename其中一个可以为空,至少一个不能为空 如果两个均不为空,默认使用filename :parm data:加密数据 filename:加密文件 :return 算法或者False ''' if data is None and filename is None: self.logger.error('解密ansible加密数据时出错,原因:参数data和filename不能同时为空') return (False, False, '参数data和filename不能同时为空') if filename is not None: result = read_file(filename) if result[0]: data = result[1] else: if data is None: self.logger.error('解密ansible文件' + filename + '时出错,无法读取文件,原因:' + result[1]) return (False, False, '无法读取文件') result = obj2bytes(data) if result[0]: b_data = result[1] else: b_data = string2bytes(data) b_data = b_data.split(b'\n') b_vault_header = b_data[0].strip() b_ciphertext = b''.join(b_data[1:]) vault_header = obj2string(b_vault_header)[1] if b_vault_header in self.b_vault_header: #这是自定义加密数据 self.logger.info('解密ansible加密数据成功,注:加密数据使用本系统自定义方法加密的') return (True, True, b_data) elif re.search('ANSIBLE_VAULT;1.1;', vault_header): #这是ansible2.3版本加密数据 # return (False, True, data) #在ansible 2.3版本中,vault加密后头部为'$ANSIBLE_VAULT;1.1;AES256',其他版本未知 if vault_header == '$ANSIBLE_VAULT;1.1;AES256': #说明加密方式为AES256,自定义加密算法一直,直接使用自定义方式进行解密 data = self.b_vault_header + b'\n' + b_ciphertext result = obj2bytes(data) if result[0]: self.logger.info('解密ansible加密数据成功,注:加密数据使用ansible2.3版本加密的') return (True, False, result[1]) else: self.logger.error( '解密ansible加密数据时失败,原因:加密数据使用ansible2.3版本加密的,' + str(result[1])) return (False, True, data) else: self.logger.error('解密ansible加密数据时失败,原因:未知格式的加密方法') return (False, True, data) else: self.logger.error('解密ansible加密数据时失败,原因:未知格式的加密方法') return (False, False, '未知格式的加密数据')