Score:1

จัดรูปแบบบันทึก SFTP ให้มีชื่อผู้ใช้ในแต่ละรายการ

ธง cn

ฉันใช้เซิร์ฟเวอร์ที่ใช้งานจริง (Debian 10, แพ็คเกจ OpenSSH มาตรฐาน) ที่มี Pure-FTPD ที่ทำงานสำหรับการเชื่อมต่อแบบดั้งเดิมและ SFTP สำหรับการเชื่อมต่อปัจจุบันทั้งหมดของเรา เซิร์ฟเวอร์ SFTP ได้รับการตั้งค่าด้วยคุก chroot ที่บันทึกผ่านอุปกรณ์ที่ผูกไว้ในคุก chroot ของผู้ใช้ สิ่งนี้ถูกเลือกโดย rsyslog และส่งไปยัง /var/log/sftp.log หลังจากนั้นฉันใช้ logstash เพื่อแยกวิเคราะห์ไฟล์นั้นและส่งต่อทุกอย่างไปยังเซิร์ฟเวอร์การแสดงภาพสำหรับผู้ใช้ขั้นสูงของเรา ผู้ใช้ขั้นสูงเข้าสู่ระบบการแสดงภาพเพื่อดูบันทึก SFTP และ FTP/FTPS ทั้งหมดในที่เดียว

บันทึก Pure-ftpd ได้รับการจัดรูปแบบในลักษณะที่ผู้ใช้ขั้นสูงของเราชอบ:

ftpd บริสุทธิ์: (testuser@hostname) [ประกาศ] /home/ftpusers/testuser//outbound/testfile.pdf ดาวน์โหลด (1765060 ไบต์, 5989.55KB/วินาที)

สิ่งนี้ดีมากเพราะในบรรทัดเดียวจะแสดงผู้ใช้และไฟล์ที่แน่นอนที่พวกเขาอัปโหลดหรือดาวน์โหลด อย่างไรก็ตาม สำหรับ SFTP สถานการณ์ไม่ดีนัก:

internal-sftp[8848]: เซสชันเปิดสำหรับผู้ใช้ทดสอบภายในเครื่องจาก [{ip_address}]
ภายใน sftp [8848]: opendir "/ ขาเข้า"
internal-sftp[8848]: realpath "/ขาเข้า/"
internal-sftp[8848]: เปิดแฟล็ก "/inbound/testfile.pdf" WRITE, CREATE, TRUNCATE 0666
internal-sftp[8848]: ปิด "/inbound/testfile.pdf" ไบต์อ่าน 0 เขียน 1734445

ในกรณีนี้ สามารถติดตามบันทึกได้ง่าย ผู้ทดสอบ เข้าสู่ระบบ เขียนไฟล์ เสร็จแล้ว แต่เรามีผู้ใช้จำนวนมากที่เข้าสู่ระบบพร้อมกัน และบันทึกจากอินสแตนซ์ของ sftp ภายในหลายรายการสามารถเกิดขึ้นได้พร้อมกัน ในกรณีนี้ วิธีเดียวที่จะติดตามกิจกรรมของผู้ใช้คือการค้นหาชื่อผู้ใช้ ผู้ทดสอบค้นหา ID กระบวนการที่บันทึก (8848 ในตัวอย่างด้านบน) จากนั้นค้นหาข้อความที่มี ID กระบวนการนั้น ผู้ใช้จำนวนมากเข้าสู่ระบบผ่าน cronjob ดังนั้นสิ่งนี้จะเกิดขึ้นทุกๆ 2 นาทีหรือมากกว่านั้น...เมื่อเรามีผู้ใช้ 300 รายเข้าสู่ระบบในช่วงเวลาปกติ คุณสามารถจินตนาการได้ว่าการตามล่า ID กระบวนการจำนวนมากนี้จะเป็นเรื่องที่เจ็บปวด

คำถามของฉัน

มีวิธีนำหน้าข้อความบันทึกแต่ละรายการจาก sftp-internal ด้วยชื่อผู้ใช้ที่สร้างบันทึกหรือไม่ สิ่งนี้จะต้องทำงานในคุก chroot ฉันไม่พบสิ่งใดเกี่ยวกับวิธีแก้ไขข้อความที่ rsyslog สร้างขึ้นเพื่อรวมชื่อผู้ใช้

ฉันต้องการเห็นสิ่งที่คล้ายกันจากบันทึก SFTP ของฉัน:

internal-sftp[8848]: (testuser) เปิดแฟล็ก "/inbound/testfile.pdf" WRITE, CREATE, TRUNCATE 0666
internal-sftp[8848]: (testuser) ปิด "/inbound/testfile.pdf" ไบต์ อ่าน 0 เขียน 1734445

สถานะปัจจุบันของการกำหนดค่า

ห่วงโซ่กระบวนการของฉันไป:

ssh -> sftp-internal -> rsyslog (บน local3.*) -> ไฟล์ /var/log/sftp.log -> logstash -> ส่งออกไปยังเซิร์ฟเวอร์การแสดงภาพ

ตัดตอนมาจากกลุ่ม chroot ของฉันใน /etc/ssh/sshd_config

จับคู่กลุ่ม sftpusers 
        ไดเรกทอรี Chroot %h
        AuthorizedKeysFile %h/.ssh/authorized_keys
        ForceCommand internal-sftp -f local3 -l INFO
        # ForceCommand internal-sftp -l VERBOSE
        อนุญาตให้ Tcp ส่งต่อหมายเลข
        X11หมายเลขการส่งต่อ

และ /etc/rsyslog.d/sftp.conf ของฉัน

local3.* -/var/log/sftp.log

คำถามที่คล้ายกัน:

คำถามนี้ เป็นเรื่องเกี่ยวกับการบันทึก SFTP เพื่อแยกไฟล์ แต่มันกล่าวถึง นี้ รายการ waybackmachine สำหรับบทความเก่าที่มีรายการบันทึก SFTP ที่มีรูปแบบสวยงามเพื่อให้ดูเหมือน xferlog มาตรฐานบทความนี้กล่าวถึงสคริปต์ Perl (จอกศักดิ์สิทธิ์) ที่จะจัดรูปแบบให้คุณ แต่อนิจจา ลิงก์เสีย ฉันสามารถเขียนสคริปต์ Python หรือ Perl เพื่อค้นหาข้อความเฉพาะสำหรับการถ่ายโอน จับรหัสกระบวนการ และค้นหาย้อนกลับเพื่อค้นหาผู้ใช้ จากนั้นพิมพ์ข้อความ xfer ที่จัดรูปแบบใหม่พร้อมชื่อผู้ใช้ออกไปยังไฟล์ แต่แน่นอนว่ามีคนแก้ปัญหานี้มาก่อนและมีวิธีแก้ไขที่ดีกว่า

ขอบคุณสำหรับความช่วยเหลือใด ๆ

Score:0
ธง cn

ฉันสามารถสร้างโซลูชันด้วย Python และ systemd นี่คือ มาก รวดเร็วและสกปรก แต่ใช้งานได้ตามวัตถุประสงค์ของฉัน ฉันใช้ไฟล์บันทึก sftp-internal และดัมพ์ไปยังไฟล์ที่ฟอร์แมตใหม่ ฉัน อย่าแก้ไข ต้นฉบับในกรณีที่ฟอร์แมตเตอร์นี้ทำผิดพลาด

สคริปต์ Python

สิ่งนี้ออกจากระบบไปยัง rsyslog เพื่อตรวจสอบและตอบกลับ SEGINT จาก systemd ใช่ สิ่งนี้ควรใช้สิ่งที่ดีกว่ารายการ แต่ python ไม่มีบัฟเฟอร์เสียงเรียกเข้าหรือระบบการจัดคิวอย่างเป็นทางการในตัว (ส่งความคิดเห็นให้ฉันหากมีบางสิ่งที่ฉันขาดหายไป) ไม่ว่าจะด้วยวิธีใด ... นี่ไม่ใช่ C!

#!/usr/bin/python3

บันทึกการนำเข้า
นำเข้าอีกครั้ง
นำเข้าระบบ
เวลานำเข้า


คลาส SFTPLogFormatter:

    def __init__(ตัวเอง, infile: str, outfile: str):
        self.logger = logging.getLogger(__ชื่อ__)
        self.logger.setLevel(logging.DEBUG)
        stdout_handler = การบันทึก StreamHandler()
        stdout_handler.setLevel (logging.DEBUG)
        stdout_handler.setFormatter(logging.Formatter('%(ชื่อระดับ)8s | %(ข้อความ)s'))
        self.logger.addHandler(stdout_handler)

        self.infile = เปิด (infile, 'r')

        # ต่อท้ายไฟล์และเก็บเพียง 1 บรรทัดในบัฟเฟอร์การเขียน (เขียนเกือบ
        # โดยทันที)
        self.outfile = เปิด (outfile, 'a', 1)

    เริ่มต้น def (ตัวเอง):
        พยายาม:
            self.logger.info('กำลังเริ่มต้นฟอร์แมตเตอร์')
            self.run()
        ยกเว้น KeyboardInterrupt:
            self.logger.warning('SIGINT ได้รับแล้ว กำลังออกอย่างสง่างาม')
            self.stop()

    @วิธีคงที่
    def tail_file (file_obj):
        ในขณะที่ทรู:
            บรรทัด = file_obj.readline()
            # เข้าสู่โหมดสลีปหากไฟล์ไม่ได้รับการอัปเดต
            ถ้าไม่ใช่สาย:
                เวลานอน(1)
                ดำเนินต่อ

            เส้นผลตอบแทน

    def ทำงาน (ตัวเอง):
        self.infile.seek(0, 2) # ข้ามไปยังจุดสิ้นสุดของไฟล์สำหรับพฤติกรรมประเภท `tail -f`
        เส้น_อ่าน = []
        สำหรับบรรทัดใน self.tail_file(self.infile): # หางไฟล์เช่น `tail -f`
            lines_read.insert(0, line) # ถือว่ารายการเหมือนกองซ้อน
            lines_read = lines_read[:2000] # trim stack เนื่องจาก python ไม่มีบัฟเฟอร์วงแหวน

            modifiedline_match = re.match(r'(.*)\[(\d+)\]: (open|close|remove name) (.*)', line) 
            ถ้าไม่ modifiedline_match:
                self.logger.info(ไลน์)
                self.outfile.write(บรรทัด)
                ดำเนินต่อ

            modified_line_procid = modifiedline_match.group(2)

            self.logger.debug(f'ค้นหาคำสั่งเปิดเซสชันสำหรับเปิด|ปิดสตริงการจับคู่ไฟล์: \"{modifyline_match.group(0)}\"')
            open_session_regex = rf'.*\[{modify_line_procid}\]: เซสชันที่เปิดสำหรับผู้ใช้ในเครื่อง (.*) จาก.*'
            open_session_match = ไม่มี
            สำหรับบรรทัดก่อนหน้าในlines_read[1:]:
                open_session_match = re.match (open_session_regex, บรรทัดก่อนหน้า)
                ถ้า open_session_match:
                    self.logger.debug(f'found session open string: \"{open_session_match.group(0)}\"')
                    หยุดพัก
            อื่น:
                #เราไม่พบอะไรเลย
                self.logger.debug('ไม่พบสตริงเซสชันเปิดสำหรับ: \"{modifyline_match.group(0)}\"')
                ดำเนินต่อ

            modified_line_start = modifiedline_match.group(1)
            modified_line_operator = modifiedline_match.group(3)
            modified_line_details = modifiedline_match.group(4)

            ชื่อผู้ใช้ = open_session_match.group(1)

            log_str = f'{modify_line_start}[{modify_line_procid}]: (ผู้ใช้={ชื่อผู้ใช้}) {modify_line_operator} {modify_line_details}\n'
            self.logger.info(log_str)
            self.outfile.write(log_str)

    def หยุด (ตัวเอง):
        self.logger.info('ทำความสะอาด')
        พยายาม:
            self.infile.close()
        ยกเว้น ข้อยกเว้นเป็น e:
            self.logger.error(f'failure while closed infile: {e}')

        พยายาม:
            self.outfile.close()
        ยกเว้น ข้อยกเว้นเป็น e:
            self.logger.error(f'failure while closed outfile: {e}')

        self.logger.info('ออก')
        sys.exit(0)


ถ้า __name__ == '__main__':
    infile = sys.argv[1]
    ไฟล์ออก = sys.argv[2]
    บริการ = SFTPLogFormatter (infile, outfile)
    บริการเริ่มต้น ()

ไฟล์บริการ

ไฟล์บริการต่อไปนี้ถูกสร้างและเปิดใช้งานใน systemd

[หน่วย]
คำอธิบาย=จัดรูปแบบข้อความบันทึกจาก sftp เพื่อให้ชื่อผู้ใช้ในไฟล์ใดๆ อ่าน เขียน และลบ ทำให้อ่านบันทึกของผู้ใช้หลายคนได้ง่ายขึ้นมาก
หลังจาก = network.target

[บริการ]
ผู้ใช้ = ราก
ประเภท = ง่าย
ExecStart=/usr/bin/python3 /home/admin/services/format_sftp_logs_with_username.py /var/log/sftp.log /var/log/sftp_with_usernames.log
KillSignal=SIGINT

[ติดตั้ง]
WantedBy=multi-user.target

ผล

ส่งผลให้ข้อความบันทึกต่อไปนี้ สังเกตการเพิ่ม (user=XYZ)

11 ก.พ. 21:22:01 ip-10-20-0-96 internal-sftp[18241]: เปิดเซสชันสำหรับผู้ใช้ในเครื่อง testuser จาก [127.0.0.1]
11 ก.พ. 21:22:02 น. ip-10-20-0-96 internal-sftp[18241]: opendir "/"
11 ก.พ. 21:22:02 น. ip-10-20-0-96 internal-sftp[18241]: closedir "/"
11 ก.พ. 21:22:05 น. ip-10-20-0-96 internal-sftp[18241]: opendir "/ ขาเข้า"
11 ก.พ. 21:22:05 น. ip-10-20-0-96 internal-sftp[18241]: closedir "/ ขาเข้า"
11 ก.พ. 21:22:10 ip-10-20-0-96 internal-sftp[18241]: opendir "/inbound/"
11 ก.พ. 21:22:10 ip-10-20-0-96 internal-sftp[18241]: closedir "/inbound/"
11 ก.พ. 21:22:12 ip-10-20-0-96 internal-sftp[18241]: (user=testuser) open "/inbound/mailhog-deployment.yaml" flag READ mode 0666
11 ก.พ. 21:22:12 ip-10-20-0-96 internal-sftp[18241]: (user=testuser) ปิด "/inbound/mailhog-deployment.yaml" ไบต์อ่าน 815 เขียน 0
11 ก.พ. 21:22:13 น. ip-10-20-0-96 internal-sftp[18241]: opendir "/inbound/"
11 ก.พ. 21:22:13 น. ip-10-20-0-96 internal-sftp[18241]: closedir "/inbound/"
11 ก.พ. 21:22:14 น. ip-10-20-0-96 internal-sftp[18241]: opendir "/inbound/"
11 ก.พ. 21:22:14 น. ip-10-20-0-96 internal-sftp[18241]: closedir "/inbound/"
11 ก.พ. 21:22:14 น. ip-10-20-0-96 internal-sftp[18241]: (user=testuser) ลบชื่อ "/inbound/mailhog-deployment.yaml"
11 ก.พ. 21:22:18 ip-10-20-0-96 internal-sftp[18241]: (user=testuser) open "/inbound/mailhog-deployment.yaml" flag WRITE,CREATE,TRUNCATE mode 0644
11 ก.พ. 21:22:18 ip-10-20-0-96 internal-sftp[18241]: (user=testuser) ปิด "/inbound/mailhog-deployment.yaml" ไบต์อ่าน 0 เขียน 815
11 ก.พ. 21:22:19 น. ip-10-20-0-96 internal-sftp[18241]: ปิดเซสชันสำหรับผู้ใช้ในเครื่อง testuser จาก [127.0.0.1]

ข้อจำกัด

บัฟเฟอร์มี 2,000 บรรทัดคอยติดตามเพื่อค้นหารหัสกระบวนการ ชนสิ่งนั้นถ้าคุณมีผู้ใช้หลายสิบหรือหลายร้อยคนเข้าสู่ระบบในทันที มิฉะนั้นสิ่งนี้ควรครอบคลุมความต้องการของเซิร์ฟเวอร์ส่วนใหญ่

โพสต์คำตอบ

คนส่วนใหญ่ไม่เข้าใจว่าการถามคำถามมากมายจะปลดล็อกการเรียนรู้และปรับปรุงความสัมพันธ์ระหว่างบุคคล ตัวอย่างเช่น ในการศึกษาของ Alison แม้ว่าผู้คนจะจำได้อย่างแม่นยำว่ามีคำถามกี่ข้อที่ถูกถามในการสนทนา แต่พวกเขาไม่เข้าใจความเชื่อมโยงระหว่างคำถามและความชอบ จากการศึกษาทั้ง 4 เรื่องที่ผู้เข้าร่วมมีส่วนร่วมในการสนทนาด้วยตนเองหรืออ่านบันทึกการสนทนาของผู้อื่น ผู้คนมักไม่ตระหนักว่าการถามคำถามจะมีอิทธิพลหรือมีอิทธิพลต่อระดับมิตรภาพระหว่างผู้สนทนา