유틸리티/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