리눅스 서버 로그인 보안 설정 가이드: Ubuntu·SUSE·Rocky Linux의 PAM, 비밀번호 정책, SSH 보안

반응형

2026년 Linux 서버 로그인 보안 설정: RHEL·Rocky, Ubuntu, SUSE 비교

서버 로그인 보안 점검에서 자주 다루는 항목은 비밀번호 복잡도, 로그인 실패 잠금, 유휴 세션 종료, root 직접 접속 제한, SSH 포트와 접근 통제다. 이 글은 RHEL·Rocky Linux 8/9 계열, Ubuntu Server 22.04/24.04 계열, SLES 15 SP7을 중심으로 설명한다. SLES 16처럼 PAM 구성이나 패키지가 달라질 수 있는 버전은 실제 파일과 지원 모듈을 먼저 확인해야 한다.

1. 변경 전에 확인할 것

PAM이나 SSH를 잘못 수정하면 원격 접속이 차단될 수 있다. 현재 SSH 세션을 유지한 상태에서 별도의 관리자 계정과 콘솔 접속 수단을 확보하고, 새 세션에서 접속을 확인한 다음 기존 세션을 종료한다. 특히 AD·LDAP·SSSD를 사용하는 서버에서는 로컬 계정만 사용하는 서버와 PAM 흐름이 다를 수 있다.

cat /etc/os-release
sshd -V 2>&1
sshd -T | grep -E '^(port|permitrootlogin|passwordauthentication|usepam|clientaliveinterval|clientalivecountmax) '
grep -R 'pam_pwquality\|pam_faillock' /etc/pam.d 2>/dev/null
ls -l /dev/null /etc/security/pwquality.conf /etc/security/faillock.conf 2>/dev/null

sshd -T는 실제로 해석된 SSH 설정을 확인하는 데 유용하다. 설정 파일에 적힌 값과 실제 적용 값이 다르면 Include 파일, 중복 지시어, Match 블록을 확인한다. 특정 사용자·접속 주소의 Match 조건은 sshd -T -C user=계정,host=호스트,addr=클라이언트IP로 따로 확인할 수 있다. :chatgpt-content-reference{index="0"}

2. 배포판별 PAM 관리 방식

배포판별 주요 인증 설정 위치
배포판 주요 PAM 관리 방식 확인할 파일
RHEL·Rocky Linux 8/9 authselect 프로필과 기능 사용 /etc/pam.d/system-auth, password-auth
Ubuntu Server pam-auth-update 및 common-* 스택 확인 /etc/pam.d/common-auth, common-password
SLES 15 SP7 pam-config 지원 모듈 확인 후 관리 /etc/pam.d/common-*, common-*-pc

RHEL 계열의 system-auth·password-auth를 직접 수정하면 authselect가 관리하는 내용과 충돌할 수 있다. SUSE 역시 pam-config가 관리하는 공통 파일을 사용하므로, 먼저 관리 도구와 현재 설정을 확인한다. :chatgpt-content-reference{index="1"}

# RHEL·Rocky
authselect current
authselect check

# Ubuntu
sudo pam-auth-update --list

# SLES
pam-config --list-modules
pam-config --query --unix

3. 비밀번호 복잡도: pam_pwquality

pam_pwquality.so는 비밀번호 변경 시 품질을 검사한다. 일반적으로 /etc/security/pwquality.conf 또는 /etc/security/pwquality.conf.d/*.conf에 기준을 둔다. 설정 파일만 만들고 PAM의 password 스택에 모듈이 연결되어 있지 않으면 기대한 대로 적용되지 않는다. :chatgpt-content-reference{index="2"}

다음은 예시 정책이다. 최소 길이와 문자 종류 요구는 조직의 보안 기준에 맞게 조정한다.

# /etc/security/pwquality.conf.d/90-local.conf
minlen = 12
minclass = 3
maxrepeat = 3
difok = 4
enforce_for_root

minclass = 3은 대문자·소문자·숫자·특수문자 중 최소 세 종류를 요구한다. enforce_for_root는 root가 비밀번호를 변경할 때도 품질 검사를 강제한다. 기존 비밀번호와 비교하는 difok의 효과는 변경 과정에서 이전 비밀번호가 PAM 모듈에 전달되는지에 영향을 받는다.

# 패키지와 PAM 연결 상태 확인
grep -R 'pam_pwquality.so' /etc/pam.d 2>/dev/null
grep -R '^[^#]' /etc/security/pwquality.conf /etc/security/pwquality.conf.d 2>/dev/null
  • RHEL·Rocky: authselect current로 프로필을 확인한 후 system-auth와 password-auth에 pam_pwquality.so가 연결되어 있는지 확인한다.
  • Ubuntu: 필요한 경우 libpam-pwquality 패키지를 설치하고 pam-auth-update 및 common-password의 결과를 확인한다.
  • SLES: pam-config --list-modules에서 지원 여부를 확인한다. 지원되는 모듈은 pam-config로 추가하고 생성된 common-password 구성을 검증한다.

비밀번호 복잡도 정책은 새 비밀번호를 설정하거나 변경할 때 적용된다. 기존에 저장된 비밀번호가 자동으로 새 규칙에 맞춰 바뀌지는 않는다.

4. 로그인 실패 횟수 제한: pam_faillock

pam_faillock.so는 인증 실패를 기록하고 기준 횟수에 도달한 계정을 일정 시간 잠근다. 다음 예시는 15분 동안 5회 실패하면 10분간 잠그는 정책이다. /etc/security/faillock.conf에 값을 적는 것과 PAM 인증 스택에서 해당 모듈을 실제 사용하는 것은 별개의 작업이다. :chatgpt-content-reference{index="3"}

# /etc/security/faillock.conf
deny = 5
fail_interval = 900
unlock_time = 600

RHEL·Rocky Linux

현재 사용 중인 authselect 프로필을 보존하면서 기능을 추가한다. 프로필 전체를 다른 것으로 바꾸면 SSSD·LDAP 등 기존 인증 구성이 바뀔 수 있다.

authselect current
sudo authselect enable-feature with-faillock
sudo authselect apply-changes
authselect check
grep -E 'pam_faillock.so' /etc/pam.d/system-auth /etc/pam.d/password-auth

Red Hat 문서도 with-faillock을 authselect 기능으로 안내한다. :chatgpt-content-reference{index="4"}

Ubuntu와 SLES

먼저 모듈 설치 여부와 관리 도구의 지원 여부를 확인한다. Ubuntu의 common-auth는 성공·실패에 따라 다음 PAM 항목을 건너뛰는 규칙이 있을 수 있다. pam_faillock.so 한 줄만 임의의 위치에 추가하면 잠금이 작동하지 않거나 정상 로그인까지 막을 수 있다. SLES도 버전별 모듈 지원을 확인한 뒤 pam-config 또는 해당 버전의 공식 절차를 따른다.

# Ubuntu
grep -n 'pam_faillock\|pam_unix\|pam_sss' /etc/pam.d/common-auth
sudo pam-auth-update --list

# SLES
pam-config --list-modules
grep -R 'pam_faillock\|pam_tally' /etc/pam.d/common-* 2>/dev/null

SLES 15 SP7 공식 문서는 공통 PAM 설정을 pam-config로 관리하도록 안내한다. 따라서 pam_faillock을 모든 SLES 버전에서 동일한 명령으로 활성화할 수 있다고 가정하면 안 된다. :chatgpt-content-reference{index="5"}

잠금 확인과 해제

# 모듈을 사용하는 시스템에서 실패 기록 확인
sudo faillock --user 사용자명

# 원인을 확인한 뒤 해당 사용자 기록 초기화
sudo faillock --user 사용자명 --reset

테스트는 별도의 일반 계정으로 수행한다. 중앙 인증 계정이나 운영용 관리자 계정을 대상으로 반복 실패 테스트를 하지 않는다. 공개키 SSH 인증 실패와 비밀번호 PAM 인증 실패는 같은 방식으로 집계되지 않을 수 있으므로 실제 사용하는 로그인 방식으로 검증한다.

5. 비밀번호 사용 기간

/etc/login.defs의 비밀번호 사용 기간 설정은 주로 새로 생성하는 로컬 계정의 기본값에 영향을 준다. 기존 계정은 chage로 따로 확인하고 변경한다.

# /etc/login.defs 예시
PASS_MAX_DAYS   90
PASS_MIN_DAYS   1
PASS_WARN_AGE   7
sudo chage -l 사용자명
sudo chage -M 90 -m 1 -W 7 사용자명
sudo chage -l 사용자명

서비스 계정, 자동화 계정, 외부 인증 계정에 같은 만료 정책을 일괄 적용하기 전에 로그인 방식과 운영 영향을 확인한다.

6. 유휴 세션 타임아웃

대화형 Bash 셸: TMOUT

로그인 후 셸에서 아무 입력도 하지 않았을 때 종료하려면 TMOUT을 설정할 수 있다. 다음 예시는 900초, 즉 15분이다.

# /etc/profile.d/99-session-timeout.sh
TMOUT=900
readonly TMOUT
export TMOUT

파일 생성 후 새로 로그인한 대화형 Bash 세션에서 echo "$TMOUT"으로 확인한다. TMOUT은 모든 종류의 세션을 동일하게 종료하는 범용 정책이 아니며, 실행 중인 작업 방식과 셸 종류에 따라 영향을 확인해야 한다.

SSH 연결 상태: ClientAliveInterval

SSH의 ClientAliveInterval은 서버가 클라이언트 응답을 확인하는 간격이다. ClientAliveCountMax와 함께 응답 없는 연결을 정리할 수 있지만, 사용자가 키보드를 입력하지 않았다는 이유만으로 종료하는 정확한 유휴 셸 타이머는 아니다. 명령 실행이나 터미널 동작과 관계된 세션 정책은 TMOUT과 구분해서 설정한다. :chatgpt-content-reference{index="6"}

ClientAliveInterval 300
ClientAliveCountMax 2

7. root 직접 SSH 접속 제한

먼저 일반 관리자 계정으로 접속하고 sudo를 사용할 수 있는지 확인한다. 이후 SSH의 root 직접 로그인을 제한한다.

PermitRootLogin no
sudo sshd -t
sudo sshd -T | grep '^permitrootlogin '
# 별도 터미널에서 일반 관리자 계정의 새 SSH 접속을 시험

PermitRootLogin no는 SSH를 통한 root 직접 로그인을 막는다. 로컬 콘솔의 root 사용이나 일반 계정으로 로그인한 뒤 sudo를 실행하는 것까지 동일하게 막는 설정은 아니다. SSH 설정 파일 경로는 일반적으로 /etc/ssh/sshd_config이며, 배포판별 sshd_config.d 파일의 포함 순서와 중복 값을 확인해야 한다. :chatgpt-content-reference{index="7"}

8. SSH 포트 변경과 방화벽

예시로 SSH 포트를 1550으로 변경한다. 포트 변경은 스캔 노출을 줄이는 운영 선택일 뿐, 강한 인증이나 접근 통제를 대신하지 않는다. 현재 접속 중인 SSH 세션은 유지하고 다음 순서로 진행한다.

  1. 서버 방화벽, 상위 방화벽, 보안 그룹에 새 포트를 허용한다.
  2. SELinux가 활성화된 RHEL·Rocky 계열에서는 SSH 포트의 SELinux 레이블을 추가한다.
  3. SSH 설정에 Port 1550을 반영하고 구문을 검사한다.
  4. SSH 서비스를 다시 읽거나 재시작한 후 새 터미널에서 접속한다.
  5. 접속에 성공한 다음에만 기존 22번 포트 허용 규칙을 정리한다.
# /etc/ssh/sshd_config 또는 실제로 읽히는 설정 파일
Port 1550
PermitRootLogin no
MaxAuthTries 4
LoginGraceTime 60

RHEL·Rocky에서 firewalld와 SELinux를 사용한다면 다음처럼 새 포트를 먼저 허용한다. semanage 명령이 없다면 해당 배포판의 정책 관리 패키지 설치 여부를 확인한다.

sudo firewall-cmd --permanent --add-port=1550/tcp
sudo firewall-cmd --reload

sudo semanage port -a -t ssh_port_t -p tcp 1550
sudo semanage port -l | grep ssh_port_t

이미 등록된 포트라면 semanage port -a가 실패할 수 있다. 오류 내용을 확인하고 기존 포트 정책과 충돌 여부를 검토한다. SUSE에서 firewalld를 사용한다면 같은 방화벽 명령을 적용할 수 있으며, 다른 방화벽을 쓰면 해당 방화벽 규칙을 변경한다.

sudo sshd -t
sudo sshd -T | grep -E '^(port|permitrootlogin|maxauthtries|logingracetime) '

# 서비스 이름은 배포판에 따라 ssh 또는 sshd
systemctl status ssh sshd --no-pager

# 적용 후 리슨 포트 확인
ss -lntp | grep ':1550'

# 다른 터미널 또는 관리자 PC에서 확인
ssh -p 1550 일반계정@서버IP

Ubuntu 24.04에서는 SSH가 systemd 소켓 활성화 방식으로 실행될 수 있다. 이 경우 설정 파일만 바꾸고 ssh.service를 재시작했다고 가정하지 말고, systemctl status ssh.socket 및 ss -lntp로 실제 리슨 포트를 확인한다. Ubuntu 24.04 릴리스 문서는 SSH 설정이 소켓 구성에도 반영되도록 처리한다고 설명한다. :chatgpt-content-reference{index="8"}

9. 적용 후 점검 명령

# SSH 설정 구문 및 실제 값
sudo sshd -t
sudo sshd -T | grep -E '^(port|permitrootlogin|passwordauthentication|usepam|clientaliveinterval|clientalivecountmax|maxauthtries) '

# 실제 리슨 포트
ss -lntp | grep -E ':(22|1550)[[:space:]]'

# 비밀번호 품질 및 로그인 실패 모듈
grep -R 'pam_pwquality.so\|pam_faillock.so' /etc/pam.d 2>/dev/null

# 현재 계정의 비밀번호 만료 상태
chage -l 사용자명

# 새 Bash 로그인에서 타임아웃 확인
echo "$TMOUT"

최종 판정은 설정 파일 존재 여부만으로 하지 않는다. 새 관리자 SSH 접속, 잘못된 비밀번호 입력 시 기록, 정상 비밀번호 변경 시도, 타임아웃 동작을 각각 별도 테스트 계정과 세션에서 확인한다.

실무 적용 순서 요약

  1. OS 버전, SSH 실행 방식, PAM 관리 도구와 중앙 인증 사용 여부를 확인한다.
  2. 콘솔 접근과 별도 관리자 계정을 확보한다.
  3. pam_pwquality와 pam_faillock의 실제 PAM 연결 상태를 확인하고 정책을 적용한다.
  4. 비밀번호 만료와 셸 타임아웃을 적용한다.
  5. root 직접 SSH 접속을 제한한다.
  6. 필요하다면 새 SSH 포트를 방화벽·SELinux·서비스에 순서대로 반영한다.
  7. 새 세션에서 접속과 정책 동작을 확인한 뒤 기존 접속과 포트 규칙을 정리한다.

참고 문서

반응형