여러가지/테스트

[프로젝트] 대상 서버 삭제 시, 전송된 파일 삭제

15June 2024. 6. 24. 16:52

● 환경

(OS) Rocky Linux release 8.10 (Green Obsidian)

(서버 1) 192.168.112.222, 로컬 서버 - 사용자

(서버 2) 192.168.112.218, 중앙 서버 - 접근 제어

 

(다음 작업 1) 대상 서버에 저장된 로그, 로컬 서버로 불러오기

(다음 작업 2) 기록된 로그 조회할 수 있는 웹페이지 제작

(다음 작업 3) 명령어 제어

(다음 작업 4) DBMS 접근 제어

 

(a) 로컬 서버

(파일) app.py

-----------------------------------------------------------------------------------------------------------------------------------------------------------------

from flask import Flask, render_template, request, redirect, url_for, flash
from flask_sqlalchemy import SQLAlchemy
import os
import subprocess

app = Flask(__name__)
app.secret_key = 'supersecretkey'

app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///ssh_config.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)

class SSHConfigEntry(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    host = db.Column(db.String(80), nullable=False)
    ip = db.Column(db.String(120), nullable=False)
    user = db.Column(db.String(80), nullable=False)
    port = db.Column(db.String(80), nullable=False)

with app.app_context():
    db.create_all()

def add_ssh_config_entry(host, ip, user, port):
    config_path = os.path.expanduser("~/.ssh/config")
    config_dir = os.path.dirname(config_path)

    if not os.path.exists(config_dir):
        os.makedirs(config_dir)

    if not os.path.exists(config_path):
        with open(config_path, 'w') as config_file:
            config_file.write("# SSH Config File\n")

    new_entry = f"""
Host {host}
    HostName {ip}
    User {user}
    Port {port}
    ProxyJump root@192.168.112.218
    """

    with open(config_path, 'a') as config_file:
        config_file.write(new_entry)

    entry = SSHConfigEntry(host=host, ip=ip, user=user, port=port)
    db.session.add(entry)
    db.session.commit()

    run_script_message = run_script(user, ip, port)
    flash("Host successfully added to SSH config and database.", "success")
    flash(run_script_message, "info")

 

# 로그 기록 파일 삭제 및 백업 복원
def delete_remote_files_and_restore_backup(remote_user, remote_host, remote_port):

    # 기존 파일 삭제 및 백업 파일 존재 시 복원
    try:

        delete_and_restore_command = f"""
        ssh -p {remote_port} {remote_user}@{remote_host} '
        if [ -f ./.bashrc ]; then
            rm ./.bashrc;
            if [ -f ./.bashrc.backup ]; then
                mv $(ls -t ./.bashrc. backup | head -1) ./.bashrc;
            fi
        fi
        if [ -f /{remote_user}/log_command.sh ]; then
            rm /{remote_user}/log_command.sh;
            if [ -f /{remote_user}/log_command. backup]; then
                mv $(ls -t /{remote_user}/log_command. backup| head -1) /{remote_user}/log_command.sh;
            fi
        fi
        '
        """

       

        # subprocess.run(['명령어', '옵션' or '매개변수'], 기타 옵션) : 명령어 실행 함

        # shell=True : 명령어 실행 시, 셸을 통해 실행하도록 지시

        # check=True : 스크립트 비정상 종료 시, CalledProcessError 예외 발생 시키는 옵션

        # stdout=subprocess.PIPE : 스크립트의 표준 출력/표준 오류 출력을 파이프로 캡처하는 옵션

        # stderr=subprocess.PIPE : 실행 중인 프로세스의 표준 오류 스트림을 파이프로 캡처하는 옵션

        # universal_newlines=True : 출력을 텍스트 형식으로 읽도록 설정

        # delete_and_restore_command에 저장된 내용 셸로 실행


        result = subprocess.run(delete_and_restore_command, shell=True, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
        return "Files successfully deleted and original files restored from backup on remote host."
    except subprocess.CalledProcessError as e:
        return "Error occurred during file deletion and restoration on remote host."


def delete_ssh_config_entry(entry_id):
    config_path = os.path.expanduser("~/.ssh/config")
    entry = SSHConfigEntry.query.get(entry_id)

    if entry:
        with open(config_path, 'r') as config_file:
            lines = config_file.readlines()

        new_lines = []
        skip = False
        for line in lines:
            if line.startswith(f"Host {entry.host}"):
                skip = True

            if skip and line.strip() == "":
                skip = False
                continue
            if not skip:
                new_lines.append(line)

        with open(config_path, 'w') as config_file:
            config_file.writelines(new_lines)

        # delete_remote_files_and_restore_backup() 함수 실행
        delete_message = delete_remote_files_and_restore_backup(entry.user, entry.ip, entry.port)
        flash(delete_message, "info")

        db.session.delete(entry)
        db.session.commit()

        return f"Entry {entry.host} deleted from {config_path} and database."
    else:
        return "Entry not found."

def run_script(remote_user, remote_host, remote_port):
    try:
        result = subprocess.run(['./setup_ssh_and_transfer.sh', remote_user, remote_host, str(remote_port)], check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
        return "SSH key exchange and file transfer completed."
    except subprocess.CalledProcessError as e:
        return "Error occurred during script execution."

@app.route('/')
def home():
    return render_template('home.html')

@app.route('/list')
def host_list():
    entries = SSHConfigEntry.query.all()
    return render_template('host_list.html', entries=entries)

@app.route('/add', methods=['POST'])
def add_entry():
    host = request.form['host']
    ip = request.form['ip']
    user = request.form['user']
    port = request.form['port']

 

    message = add_ssh_config_entry(host, ip, user, port)

    flash(message)
    return redirect(url_for('home'))



@app.route('/delete/<int:entry_id>', methods=['POST'])
def delete_entry(entry_id):
    message = delete_ssh_config_entry(entry_id)
    flash(message)
    return redirect(url_for('host_list'))

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=2024)

-----------------------------------------------------------------------------------------------------------------------------------------------------------------