유틸리티/JbDesk

JbDesk 3.1편-Python fabric 으로 원격 커맨드 실행

제이브레인 2025. 4. 8. 17:32

Python의 Fabric은 서버에 SSH로 접속해서 원격 명령을 실행하거나 배포 자동화를 할 수 있도록 도와주는 Python 기반의 도구 및 라이브러리입니다. 예전에는 주로 배포 스크립트 자동화 용도로 많이 사용되었고, 최근에는 DevOps나 CI/CD 파이프라인에도 활용되고 있습니다.

1) fabric 설치

pip install fabric

 

설치 후 버전은 확인은 다음과 같습니다.

fab --version

 

Fabric 3.2.2 가 설치되었는데 설치 시점에 따라 버전은 다를 수 있습니다.

(jbdesk38_64) PS D:\repo\jbDeskExample> fab --version
Fabric 3.2.2
Paramiko 3.5.1
Invoke 2.2.0

 

2) fabric 코드 생성

ChatGPT 에 사용한 프롬프트입니다.

python 으로 host_name, user_name, password 를 입력 받아서 os name, version 을 리턴하는 함수를 만들어주세요. 
그리고 host_name, user_name, password 를 파라미터로 받아서 실행하는 예제를 만들어주세요. 
파라미터는  fab_os_info.py -host_name=192.168.56.20 -user_name=vagrant -password=vagrant 와 같이 실행하는 코드를 만들어주세요. 
코드를 만든 후에 테스트 해보고 오류가 없는 코드로 알려주세요.

 

✅ fab_os_info.py (전체 코드)

아래 코드는 다음에서 다운받을 수 있습니다.

git clone git@github.com:jbpark/jbDeskExample.git
cd jbDeskExample/jbDesk/ch3.1

 

import argparse
from fabric import Connection
from invoke.exceptions import UnexpectedExit

def get_os_info(host_name: str, user_name: str, password: str) -> str:
    """
    SSH로 접속해서 OS 이름과 버전을 반환합니다.
    """
    try:
        conn = Connection(
            host=host_name,
            user=user_name,
            connect_kwargs={"password": password}
        )

        try:
            result = conn.run("cat /etc/os-release", hide=True)
            lines = result.stdout.strip().splitlines()
            info = {}
            for line in lines:
                if "=" in line:
                    key, value = line.split("=", 1)
                    info[key.strip()] = value.strip().strip('"')
            return f"{info.get('NAME', 'Unknown OS')} {info.get('VERSION', '')}"

        except UnexpectedExit:
            # /etc/os-release가 없는 경우 (예: CentOS 6)
            result = conn.run("cat /etc/redhat-release", hide=True)
            return result.stdout.strip()

    except Exception as e:
        return f"❌ 접속 실패: {str(e)}"

def main():
    parser = argparse.ArgumentParser(description="Fabric을 사용하여 원격 서버 OS 정보를 가져옵니다.")
    parser.add_argument("-host_name", required=True, help="호스트 이름 또는 IP")
    parser.add_argument("-user_name", required=True, help="SSH 사용자 이름")
    parser.add_argument("-password", required=True, help="SSH 비밀번호")

    args = parser.parse_args()

    os_info = get_os_info(args.host_name, args.user_name, args.password)
    print("✅ OS 정보:", os_info)

if __name__ == "__main__":
    main()

 

✅ 실행 방법

python fab_os_info.py -host_name=192.168.56.20 -user_name=vagrant -password=vagrant

 

3) 테스트 환경 구성

vagrant 로 OS 가 다른 VM 2개를 만들어서 테스트해보겠습니다.

ChatGPT 프롬프트입니다.

Vagrant 로 다음과 같은 환경을 만들어주세요.
그리고 ssh 로그인 가능하게 해주세요.

host_name : rocky9-first
ip : 192.168.56.30
os : rocky9

host_name : ubuntu-second
ip : 192.168.56.31
os : ubuntu

위 환경을 기반으로 Vagrantfile을 아래와 같이 구성했습니다:


✅ 구성 요약

 

VM 이름 P 주소 OS SSH 비밀번호 로그인
rocky9-first 192.168.56.20 Rocky Linux 9 가능 (vagrant/vagrant)
ubuntu-second 192.168.56.21 Ubuntu 22.04 가능 (vagrant/vagrant)

✅ Vagrantfile

Vagrant.configure("2") do |config|
  # 공통 설정
  config.vm.provider "virtualbox" do |vb|
    vb.memory = 1024
    vb.cpus = 1
  end

  # Rocky Linux 9 VM
  config.vm.define "rocky9-first" do |rocky|
    rocky.vm.box = "generic/rocky9"
    rocky.vm.hostname = "rocky9-first"
    rocky.vm.network "private_network", ip: "192.168.56.30"

    rocky.vm.provision "shell", inline: <<-SHELL
      echo "[+] Enabling SSH password login on Rocky Linux..."

      # 비밀번호 로그인 허용
      sed -i 's/^#PasswordAuthentication no/PasswordAuthentication yes/' /etc/ssh/sshd_config
      sed -i 's/^PasswordAuthentication no/PasswordAuthentication yes/' /etc/ssh/sshd_config
      echo 'vagrant:vagrant' | chpasswd
      systemctl restart sshd
    SHELL
  end

  # Ubuntu VM
  config.vm.define "ubuntu-second" do |ubuntu|
    ubuntu.vm.box = "generic/ubuntu2204"
    ubuntu.vm.hostname = "ubuntu-second"
    ubuntu.vm.network "private_network", ip: "192.168.56.31"

    ubuntu.vm.provision "shell", inline: <<-SHELL
      echo "[+] Enabling SSH password login on Ubuntu..."

      sed -i 's/^#PasswordAuthentication no/PasswordAuthentication yes/' /etc/ssh/sshd_config
      sed -i 's/^PasswordAuthentication no/PasswordAuthentication yes/' /etc/ssh/sshd_config
      echo 'vagrant:vagrant' | chpasswd
      systemctl restart sshd
    SHELL
  end
end

✅ 사용 방법

  • 위 코드를 Vagrantfile로 저장
  • VM 생성 및 부팅:
vagrant up
  • SSH 테스트:
ssh vagrant@192.168.56.20  # Rocky
ssh vagrant@192.168.56.21  # Ubuntu
# 비밀번호: vagrant
 
 

또는 Fabric 사용 시:

python fab_os_info.py -host_name=192.168.56.30 -user_name=vagrant -password=vagrant
python fab_os_info.py -host_name=192.168.56.31 -user_name=vagrant -password=vagrant
 
실행 결과는 다음과 같습니다.
(jbdesk38_64) PS D:\repo\jbDeskExample\jbdesk\ch3.1> python fab_os_info.py -host_name 192.168.56.20 -user_name vagrant -password vagrant
✅ OS 정보: Rocky Linux 9.3 (Blue Onyx)
(jbdesk38_64) PS D:\repo\jbDeskExample\jbdesk\ch3.1> python fab_os_info.py -host_name 192.168.56.21 -user_name vagrant -password vagrant
✅ OS 정보: Ubuntu 22.04.3 LTS (Jammy Jellyfish)
 
 

4) 실행 오류

4.1 Bad authentication type

(jbdesk38_64) PS D:\repo\jbDeskExample\jbdesk\ch3.1> python fab_os_info.py -host_name 192.168.56.20 -user_name vagrant -password vagrant
✅ OS 정보: ❌ 접속 실패: Bad authentication type; allowed types: ['publickey', 'gssapi-keyex', 'gssapi-with-mic']

 

이 오류는 SSH 서버가 비밀번호 인증을 아예 허용하지 않고, 공개키 인증만 허용할 때 발생합니다.

✅ 해결 방법 1: 서버에서 비밀번호 인증 허용

⚠️ 보안상 실서비스에서는 권장하지 않지만, 테스트 환경에서는 가능

 

- 서버에 접속 (이미 공개키로 접속 가능한 상태여야 함)

- sshd_config 수정:

sudo nano /etc/ssh/sshd_config

아래 항목 변경:

PasswordAuthentication yes

- SSH 서버 재시작:

 
sudo systemctl restart sshd