[태그:] SSH

  • 방화벽과 OpenSSH로 서버 보안 강화하기: 실무에서 바로 쓰는 완벽 가이드

    안녕하세요, 성장하는 개발자 여러분!

    “서버 보안”이라고 하면 뭔가 복잡하고 어려운 것처럼 느껴지시나요? 하지만 실제로는 몇 가지 핵심 원칙만 제대로 지키면 90%의 공격을 막을 수 있습니다. 오늘은 가장 기본이면서도 강력한 두 가지 보안 도구인 방화벽과 OpenSSH를 활용해 서버를 안전하게 지키는 방법을 알려드리겠습니다.

    실무에서 제가 직접 겪었던 보안 사고들과 그 해결 과정을 통해 배운 실전 노하우를 함께 공유하니, 끝까지 집중해서 읽어보시길 바랍니다! 🔒

    1. 서버 보안의 기본 원칙: 최소 권한과 다층 방어

    보안의 황금률

    1. 최소 권한 원칙: 꼭 필요한 것만 열어두기
    2. 다층 방어: 하나의 보안 장치에 의존하지 않기
    3. 지속적인 모니터링: 로그를 통한 이상 징후 감지
    4. 정기적인 업데이트: 보안 패치는 최우선

    실무에서 자주 발생하는 보안 위협들

    # 실제 공격 시도 로그 예시
    grep "Failed password" /var/log/secure | tail -5
    # Jan 15 14:32:11 server sshd[1234]: Failed password for root from 192.168.1.100 port 22
    # Jan 15 14:32:13 server sshd[1235]: Failed password for admin from 192.168.1.100 port 22
    # Jan 15 14:32:15 server sshd[1236]: Failed password for user from 192.168.1.100 port 22
    
    # 의심스러운 접속 시도 확인
    journalctl -u sshd | grep "authentication failure" | tail -10

    이런 로그들이 보이시나요? 이미 여러분의 서버가 공격받고 있을 수 있습니다!

    2. Firewalld: 현대적인 방화벽 관리의 핵심

    Firewalld vs iptables: 왜 Firewalld를 써야 할까?

    Firewalld의 장점:

    • 동적 설정 변경: 서비스 재시작 없이 즉시 적용
    • Zone 기반 관리: 네트워크 환경별 정책 분리
    • GUI 지원: 명령어뿐만 아니라 그래픽 도구도 제공
    • XML 설정: 사람이 읽기 쉬운 설정 파일

    기본 설정과 상태 확인

    # 1. Firewalld 상태 확인
    sudo systemctl status firewalld
    sudo firewall-cmd --state
    
    # 2. 현재 설정 확인
    sudo firewall-cmd --list-all
    
    # 3. 활성 영역(Zone) 확인
    sudo firewall-cmd --get-active-zones
    
    # 4. 기본 영역 확인
    sudo firewall-cmd --get-default-zone

    Zone 개념 이해하기

    Firewalld의 가장 강력한 기능 중 하나가 Zone입니다:

    # 사용 가능한 모든 Zone 확인
    sudo firewall-cmd --get-zones
    # block dmz drop external home internal public trusted work
    
    # 각 Zone의 특성
    # - drop: 모든 들어오는 패킷 차단 (가장 엄격)
    # - block: 들어오는 패킷 거부 응답
    # - public: 기본 Zone, SSH와 DHCP 클라이언트만 허용
    # - external: 외부 네트워크용, NAT 환경에서 사용
    # - internal: 내부 네트워크용, 더 많은 서비스 허용
    # - home: 홈 네트워크용, 파일 공유 등 허용
    # - work: 직장 네트워크용
    # - trusted: 모든 패킷 허용 (가장 관대)

    실무 시나리오별 방화벽 설정

    시나리오 1: 웹 서버 보안 설정

    # 기본 Zone을 public으로 설정 (이미 기본값)
    sudo firewall-cmd --set-default-zone=public
    
    # HTTP/HTTPS 서비스 영구 허용
    sudo firewall-cmd --permanent --add-service=http
    sudo firewall-cmd --permanent --add-service=https
    
    # 커스텀 포트 허용 (예: 8080)
    sudo firewall-cmd --permanent --add-port=8080/tcp
    
    # 설정 적용
    sudo firewall-cmd --reload
    
    # 확인
    sudo firewall-cmd --list-services
    sudo firewall-cmd --list-ports

    시나리오 2: 데이터베이스 서버 보안 강화

    # 특정 IP에서만 MySQL 접근 허용
    sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.1.0/24" port protocol="tcp" port="3306" accept'
    
    # 특정 서버에서만 PostgreSQL 접근 허용
    sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.1.100" port protocol="tcp" port="5432" accept'
    
    # 모든 외부 접근 차단하고 내부 네트워크만 허용
    sudo firewall-cmd --permanent --zone=internal --add-source=192.168.1.0/24
    sudo firewall-cmd --permanent --zone=internal --add-service=mysql
    sudo firewall-cmd --permanent --zone=internal --add-service=postgresql
    
    sudo firewall-cmd --reload

    시나리오 3: 개발 서버 임시 포트 열기

    # 임시로 포트 열기 (재부팅 시 삭제됨)
    sudo firewall-cmd --add-port=3000/tcp
    sudo firewall-cmd --add-port=8080/tcp
    
    # 확인
    sudo firewall-cmd --list-ports
    
    # 영구 설정으로 변경 (필요한 경우)
    sudo firewall-cmd --runtime-to-permanent

    Rich Rules: 고급 방화벽 정책

    # 1. 특정 시간대에만 SSH 접근 허용 (고급 설정)
    # 평일 9시-18시에만 특정 IP에서 SSH 접근 허용
    sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.1.100" service name="ssh" log prefix="SSH Access: " level="info" limit value="3/m" accept'
    
    # 2. 무차별 대입 공격 방지
    # 동일 IP에서 5번 이상 실패 시 10분간 차단
    sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.1.0/24" service name="ssh" log prefix="SSH Brute Force: " level="warning" limit value="5/m" drop'
    
    # 3. 포트 스캔 감지 및 차단
    sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" port port="22" protocol="tcp" log prefix="SSH Scan: " level="warning" limit value="1/m" accept'

    방화벽 로그 모니터링

    # 방화벽 로그 실시간 모니터링
    sudo journalctl -u firewalld -f
    
    # 특정 키워드로 로그 필터링
    sudo journalctl -u firewalld | grep "SSH"
    sudo journalctl -u firewalld | grep "DROP"
    
    # 로그 분석 스크립트
    #!/bin/bash
    echo "=== 오늘의 방화벽 로그 요약 ==="
    echo "총 차단된 연결 수:"
    sudo journalctl -u firewalld --since today | grep -c "DROP"
    echo "SSH 접근 시도:"
    sudo journalctl -u firewalld --since today | grep -c "SSH"
    echo "가장 많이 시도한 IP:"
    sudo journalctl -u firewalld --since today | grep -oP 'from K[0-9.]+' | sort | uniq -c | sort -nr | head -5

    3. OpenSSH: 안전한 원격 접속의 모든 것

    SSH 기본 보안 강화

    1. SSH 설정 파일 최적화

    # SSH 설정 파일 백업
    sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.backup
    
    # 주요 보안 설정
    sudo nano /etc/ssh/sshd_config

    필수 보안 설정들:

    # /etc/ssh/sshd_config 권장 설정
    
    # 1. 기본 포트 변경 (선택사항)
    Port 2222
    
    # 2. Root 로그인 완전 차단
    PermitRootLogin no
    
    # 3. 패스워드 로그인 비활성화 (키 인증만 허용)
    PasswordAuthentication no
    ChallengeResponseAuthentication no
    UsePAM no
    
    # 4. 빈 패스워드 금지
    PermitEmptyPasswords no
    
    # 5. X11 포워딩 비활성화 (필요없는 경우)
    X11Forwarding no
    
    # 6. 로그인 시간 제한
    LoginGraceTime 30
    
    # 7. 최대 동시 세션 제한
    MaxSessions 3
    
    # 8. 특정 사용자만 SSH 접근 허용
    AllowUsers developer admin
    
    # 9. 특정 그룹만 SSH 접근 허용
    AllowGroups ssh-users
    
    # 10. 연결 유지 설정
    ClientAliveInterval 300
    ClientAliveCountMax 2

    설정 후 서비스 재시작:

    # 설정 파일 문법 검사
    sudo sshd -t
    
    # SSH 서비스 재시작
    sudo systemctl restart sshd
    
    # 상태 확인
    sudo systemctl status sshd

    SSH 키 기반 인증: 패스워드보다 1000배 안전한 방법

    1. SSH 키 쌍 생성

    # RSA 키 생성 (4096비트, 더 안전)
    ssh-keygen -t rsa -b 4096 -C "your-email@domain.com"
    
    # 또는 더 최신의 Ed25519 키 (권장)
    ssh-keygen -t ed25519 -C "your-email@domain.com"
    
    # 키 생성 시 옵션들
    # -t: 키 타입 (rsa, ed25519)
    # -b: 키 비트 수
    # -C: 코멘트 (보통 이메일)
    # -f: 키 파일 이름 지정

    2. 공개키 서버에 복사

    # 자동으로 공개키 복사
    ssh-copy-id username@server-ip
    
    # 커스텀 포트 사용 시
    ssh-copy-id -p 2222 username@server-ip
    
    # 특정 키 파일 지정
    ssh-copy-id -i ~/.ssh/custom_key.pub username@server-ip
    
    # 수동으로 복사 (ssh-copy-id 사용 불가 시)
    cat ~/.ssh/id_rsa.pub | ssh username@server-ip "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"

    3. SSH 키 관리 및 보안

    # 키 권한 설정 (매우 중요!)
    chmod 700 ~/.ssh
    chmod 600 ~/.ssh/id_rsa
    chmod 644 ~/.ssh/id_rsa.pub
    chmod 600 ~/.ssh/authorized_keys
    
    # 여러 키 관리를 위한 SSH config 설정
    nano ~/.ssh/config

    SSH Config 예시:

    # ~/.ssh/config
    Host prod-server
        HostName 192.168.1.100
        Port 2222
        User developer
        IdentityFile ~/.ssh/prod_server_key
    
    Host dev-server
        HostName 192.168.1.200
        Port 22
        User admin
        IdentityFile ~/.ssh/dev_server_key
    
    Host git-server
        HostName github.com
        User git
        IdentityFile ~/.ssh/github_key
    
    # 모든 서버에 대한 기본 설정
    Host *
        ServerAliveInterval 60
        ServerAliveCountMax 3
        StrictHostKeyChecking ask
        UserKnownHostsFile ~/.ssh/known_hosts

    사용법:

    # 간단하게 접속
    ssh prod-server
    ssh dev-server
    
    # 파일 복사도 편리하게
    scp myfile.txt prod-server:~/

    SSH 터널링: 안전한 포트 포워딩

    로컬 포트 포워딩

    # 원격 서버의 MySQL을 로컬에서 접근
    ssh -L 3306:localhost:3306 username@server-ip
    
    # 원격 서버의 웹 애플리케이션을 로컬에서 접근
    ssh -L 8080:localhost:80 username@server-ip
    
    # 백그라운드 실행
    ssh -f -N -L 3306:localhost:3306 username@server-ip

    리모트 포트 포워딩

    # 로컬의 서비스를 원격에서 접근 가능하게 (주의 필요)
    ssh -R 8080:localhost:3000 username@server-ip
    
    # 백그라운드 실행
    ssh -f -N -R 8080:localhost:3000 username@server-ip

    SOCKS 프록시

    # SOCKS 프록시 생성
    ssh -D 1080 username@server-ip
    
    # 브라우저에서 localhost:1080을 SOCKS 프록시로 설정하면
    # 모든 트래픽이 서버를 통해 전송됨

    4. 실전 보안 모니터링과 자동화

    SSH 접속 로그 분석

    # 성공한 SSH 로그인 확인
    sudo grep "Accepted" /var/log/secure
    
    # 실패한 SSH 로그인 확인
    sudo grep "Failed password" /var/log/secure
    
    # 특정 IP의 접속 시도 분석
    sudo grep "192.168.1.100" /var/log/secure
    
    # 오늘의 SSH 활동 요약
    sudo journalctl -u sshd --since today | grep -E "(Accepted|Failed)"

    자동 보안 모니터링 스크립트

    #!/bin/bash
    # ssh_monitor.sh - SSH 보안 모니터링 스크립트
    
    LOG_FILE="/var/log/ssh_monitor.log"
    SECURE_LOG="/var/log/secure"
    ALERT_THRESHOLD=5
    
    echo "=== SSH 보안 모니터링 시작: $(date) ===" >> $LOG_FILE
    
    # 1. 실패한 로그인 시도 카운트
    FAILED_ATTEMPTS=$(grep "Failed password" $SECURE_LOG | grep "$(date +%b %d)" | wc -l)
    
    if [ $FAILED_ATTEMPTS -gt $ALERT_THRESHOLD ]; then
        echo "⚠️  경고: 오늘 $FAILED_ATTEMPTS 번의 로그인 실패가 발생했습니다!" >> $LOG_FILE
    
        # 가장 많이 시도한 IP 찾기
        TOP_ATTACKERS=$(grep "Failed password" $SECURE_LOG | grep "$(date +%b %d)" | 
                       grep -oP 'from K[0-9.]+' | sort | uniq -c | sort -nr | head -3)
    
        echo "주요 공격 IP들:" >> $LOG_FILE
        echo "$TOP_ATTACKERS" >> $LOG_FILE
    
        # 자동 차단 (선택사항)
        echo "$TOP_ATTACKERS" | while read count ip; do
            if [ $count -gt 10 ]; then
                echo "IP $ip 자동 차단 (시도 횟수: $count)" >> $LOG_FILE
                sudo firewall-cmd --add-rich-rule="rule family='ipv4' source address='$ip' drop"
            fi
        done
    fi
    
    # 2. 새로운 SSH 키 추가 감지
    AUTHORIZED_KEYS="/home/*/.ssh/authorized_keys"
    for auth_file in $AUTHORIZED_KEYS; do
        if [ -f "$auth_file" ]; then
            KEY_COUNT=$(wc -l < "$auth_file")
            echo "$(dirname $auth_file): $KEY_COUNT 개의 SSH 키" >> $LOG_FILE
        fi
    done
    
    # 3. Root 로그인 시도 감지
    ROOT_ATTEMPTS=$(grep "Failed password for root" $SECURE_LOG | grep "$(date +%b %d)" | wc -l)
    if [ $ROOT_ATTEMPTS -gt 0 ]; then
        echo "🚨 위험: Root 계정으로 $ROOT_ATTEMPTS 번의 로그인 시도가 있었습니다!" >> $LOG_FILE
    fi
    
    echo "=== 모니터링 완료: $(date) ===" >> $LOG_FILE
    echo "" >> $LOG_FILE

    Fail2Ban: 자동 침입 차단 시스템

    # Fail2Ban 설치
    sudo dnf install fail2ban -y
    sudo systemctl enable fail2ban
    sudo systemctl start fail2ban
    
    # SSH 보호 설정
    sudo nano /etc/fail2ban/jail.local
    [DEFAULT]
    # 차단 시간 (초)
    bantime = 3600
    # 관찰 시간 (초)
    findtime = 600
    # 최대 시도 횟수
    maxretry = 5

    [sshd]

    enabled = true port = ssh logpath = /var/log/secure maxretry = 3 bantime = 7200

    # Fail2Ban 재시작
    sudo systemctl restart fail2ban
    
    # 상태 확인
    sudo fail2ban-client status
    sudo fail2ban-client status sshd
    
    # 차단된 IP 확인
    sudo fail2ban-client get sshd banned
    
    # 수동으로 IP 차단/해제
    sudo fail2ban-client set sshd banip 192.168.1.100
    sudo fail2ban-client set sshd unbanip 192.168.1.100

    5. 보안 점검 체크리스트와 베스트 프랙티스

    일일 보안 점검 체크리스트

    #!/bin/bash
    # daily_security_check.sh
    
    echo "=== 일일 보안 점검 $(date) ==="
    
    # 1. 시스템 업데이트 확인
    echo "1. 시스템 업데이트 상태:"
    dnf check-update | wc -l
    
    # 2. 방화벽 상태 확인
    echo "2. 방화벽 상태:"
    sudo systemctl is-active firewalld
    
    # 3. SSH 서비스 상태 확인
    echo "3. SSH 서비스 상태:"
    sudo systemctl is-active sshd
    
    # 4. 활성 네트워크 연결 확인
    echo "4. 현재 활성 연결 (상위 10개):"
    sudo ss -tuln | head -10
    
    # 5. 마지막 로그인 확인
    echo "5. 최근 로그인 기록:"
    last -n 5
    
    # 6. 수상한 프로세스 확인
    echo "6. 높은 CPU 사용 프로세스:"
    ps aux --sort=-%cpu | head -5
    
    # 7. 디스크 사용량 확인
    echo "7. 디스크 사용량:"
    df -h | grep -v tmpfs
    
    # 8. 실패한 로그인 시도
    echo "8. 오늘의 실패한 로그인 시도:"
    sudo grep "Failed password" /var/log/secure | grep "$(date +%b %d)" | wc -l
    
    echo "=== 점검 완료 ==="

    월간 보안 리뷰 체크리스트

    • [ ] 사용자 계정 검토: 불필요한 계정 제거
    • [ ] SSH 키 정리: 사용하지 않는 키 제거
    • [ ] 방화벽 규칙 점검: 불필요한 규칙 정리
    • [ ] 로그 분석: 수상한 활동 패턴 확인
    • [ ] 보안 패치 적용: 최신 보안 업데이트
    • [ ] 백업 확인: 설정 파일 백업 상태 점검

    보안 사고 대응 절차

    1. 즉시 대응 (5분 이내)

    # 의심스러운 IP 즉시 차단
    sudo firewall-cmd --add-rich-rule="rule family='ipv4' source address='SUSPICIOUS_IP' drop"
    
    # 모든 SSH 연결 확인
    who
    w
    
    # 의심스러운 세션 강제 종료
    sudo pkill -u suspicious_user
    
    # 긴급 상황 시 SSH 포트 임시 변경
    sudo sed -i 's/Port 22/Port 2222/' /etc/ssh/sshd_config
    sudo systemctl restart sshd

    2. 조사 및 분석 (30분 이내)

    # 상세 로그 분석
    sudo grep -E "($(date +%b %d)|$(date -d yesterday +%b %d))" /var/log/secure > security_incident_$(date +%Y%m%d).log
    
    # 네트워크 연결 상태 저장
    sudo ss -tuln > network_status_$(date +%Y%m%d).log
    
    # 프로세스 상태 저장
    ps aux > process_status_$(date +%Y%m%d).log

    3. 복구 및 강화 (1시간 이내)

    # 패스워드 강제 변경
    sudo passwd username
    
    # SSH 키 교체
    ssh-keygen -t ed25519 -C "incident-response-$(date +%Y%m%d)"
    
    # 방화벽 규칙 강화
    sudo firewall-cmd --set-default-zone=drop
    sudo firewall-cmd --zone=trusted --add-source=ADMIN_IP

    마치며: 보안은 여정이지 목적지가 아닙니다

    핵심 원칙 재정리

    1. 기본을 충실히: 방화벽 + SSH 키 인증만으로도 90% 보안 확보
    2. 지속적인 모니터링: 로그 분석과 이상 징후 감지
    3. 정기적인 점검: 보안 설정과 계정 관리
    4. 빠른 대응: 사고 발생 시 신속한 차단과 분석

    실무에서 기억할 점

    • 편의성 vs 보안: 항상 트레이드오프 관계임을 인식
    • 문서화: 모든 보안 설정과 대응 절차를 문서로 남기기
    • 팀 공유: 보안 지식과 절차를 팀원들과 공유
    • 지속적인 학습: 새로운 공격 기법과 방어 방법 학습

    다음 단계

    오늘 배운 내용을 바탕으로:

    1. 테스트 서버에서 연습: 실제 운영 서버에 적용하기 전에 충분히 연습
    2. 모니터링 시스템 구축: 자동화된 보안 모니터링 환경 구성
    3. 백업 계획 수립: 보안 사고 시 빠른 복구를 위한 백업 전략
    4. 팀 내 보안 문화 조성: 개발팀 전체가 보안을 의식하는 문화 만들기

    기억하세요: 완벽한 보안은 존재하지 않습니다. 하지만 기본적인 보안 수칙을 지키는 것만으로도 대부분의 공격으로부터 서버를 안전하게 지킬 수 있습니다.

    보안은 한 번 설정하고 끝나는 것이 아니라 지속적으로 관리하고 개선해야 하는 여정입니다. 오늘부터 여러분도 이 여정에 함께해주세요! 🛡️


    다음 포스트에서는 “로그 관리와 모니터링 실전 가이드”에서 더 고급 모니터링 기법들을 다뤄보겠습니다. 기대해 주세요!