대상 OS: Rocky Linux 9

SSH 무차별 대입을 막는 방법은 여러 가지지만, “계정 단위로 반복 실패를 제어”하는 건 기본 중 기본입니다.
IP 차단(Fail2ban, 방화벽)만 쓰면 분산 공격에 약하고, 운영자 IP가 바뀌는 순간 오탐도 생깁니다.
반대로 계정 잠금은 공격자가 IP를 바꿔도 같은 계정을 계속 두드리면 제약이 걸립니다.
Rocky Linux 9에서는 PAM의 `faillock`으로 로그인 실패 횟수 기반 잠금 정책을 표준 방식으로 운영할 수 있습니다.

이 글은 Rocky Linux 9에서 authselect를 이용해 PAM faillock을 안전하게 적용하고, SSH 무차별 대입을 완화하는 계정 잠금 정책(임계치/잠금 시간/관리자 복구/오탐 줄이기)을 실전 관점에서 정리합니다.

---

1) 계정 잠금 정책이 해결하는 것

1) 분산 공격(여러 IP에서 같은 계정을 두드림)에 대한 완화

2) 동일 계정을 대상으로 하는 크리덴셜 스터핑/무차별 대입 비용 증가

3) 보안 이벤트(실패 누적)를 로그/감사로 남기기 쉬움

4) “IP 차단”과 달리 사용자 정책으로 문서화/내부 통제가 쉬움

주의: 계정 잠금은 양날의 검입니다. 임계치가 너무 빡세면 공격자가 의도적으로 로그인 실패를 반복해서 “정상 사용자를 잠그는 DoS”가 가능합니다.
그래서 이 정책은 반드시
- 임계치/잠금 시간 튜닝
- 관리자 복구 절차
- 관리망/관리 계정 운영 방식
과 함께 설계해야 합니다.

---

2) 적용 전 점검: 현재 인증 스택(authselect) 확인

Rocky 9(RHEL9 계열)는 PAM 파일을 직접 편집하기보다 authselect 프로파일로 관리하는 것이 권장됩니다.

1) authselect 상태 확인

sudo authselect current

2) 현재 PAM 설정 파일 위치 확인

ls -la /etc/pam.d | sed -n '1,120p'

3) SSH가 PAM을 사용 중인지 확인

sudo sshd -T | grep -i usepam

`UsePAM yes`여야 PAM 정책이 SSH 로그인에 적용됩니다.

---

3) faillock 모듈/도구 준비

1) faillock 명령 확인

command -v faillock || echo "faillock not found"
rpm -q util-linux || true

2) 실패 기록 저장 경로 확인(환경에 따라 다를 수 있음)

sudo faillock --help | head -n 40

---

4) authselect로 faillock 기능 활성화

여기서부터가 핵심입니다. PAM 파일을 직접 수정하면 업데이트/정책 적용 과정에서 덮어쓰여 운영이 꼬일 수 있습니다.

1) authselect에서 faillock 기능 활성화

sudo authselect enable-feature with-faillock

2) 변경 적용

sudo authselect apply-changes

3) PAM 구성에 faillock이 들어갔는지 확인

grep -R "pam_faillock" -n /etc/pam.d | head -n 60

---

5) 정책 값 설정: deny/unlock_time/fail_interval 튜닝

RHEL9 계열에서 faillock 파라미터는 보통 `/etc/security/faillock.conf`로 관리합니다.
(환경에 따라 기본 파일이 없을 수도 있으니 생성해 운영 표준으로 두는 게 좋습니다.)

1) faillock 설정 파일 생성/수정(예시)

sudo tee /etc/security/faillock.conf >/dev/null  15분 동안의 실패를 집계

fail_interval = 900

# 잠금 해제까지의 시간(초)
# unlock_time=1800 -> 30분 잠금

unlock_time = 1800

# root 계정 처리 정책은 매우 신중해야 함.
# even_deny_root 를 켜면 root도 잠길 수 있어 사고 위험이 큼.
# 기본은 주석 처리(꺼둠).
# even_deny_root

# root 잠금이 필요하다면, console 접근/비상계정/SSH CA 등 복구 경로가 먼저.
EOF

2) 적용 후 SSH 재시작(정책 변경 반영 확인)

sudo systemctl restart sshd
sudo systemctl status sshd --no-pager

운영 팁
- `deny=5`, `unlock_time=1800`은 “시작점”입니다.
- 공격이 심하면 deny를 낮추고 unlock_time을 늘리기보다, 먼저 SSH 노출 최소화(VPN/allowlist)와 함께 조합하세요.

---

6) 동작 확인: 실패 누적/잠금/해제 흐름

테스트는 가능하면 테스트 계정으로, 콘솔(또는 별도 세션 유지) 접근이 가능한 상태에서 진행하세요.

1) 특정 사용자 실패 기록 조회

sudo faillock --user testuser

2) 실패 카운터 초기화(관리자 복구)

sudo faillock --user testuser --reset

3) 잠금 상태가 의심될 때 빠른 진단(로그)

sudo journalctl -u sshd -n 200 --no-pager
sudo journalctl -t sshd -n 200 --no-pager || true

---

7) 오탐/운영 사고를 줄이는 설계 포인트

1) 관리자 계정은 ‘관리망(VPN)’에서만 접속하도록 구조를 바꾼다

2) MFA/SSH CA/키 인증을 기본으로 하고, 비밀번호 로그인 자체를 줄인다

3) 잠금 시간을 길게 잡기 전에 “잠금 해제 절차”를 문서화한다

4) 배치/자동화 계정은 비밀번호 로그인을 쓰지 않게 한다(키 기반, 인증서, 또는 별도 접근 채널)

5) 계정 잠금 DoS를 고려해 fail_interval과 deny를 조정한다

- 너무 짧은 fail_interval은 우발적 실수를 과도하게 벌줄 수 있음
- 너무 긴 unlock_time은 운영 사고를 키움

---

8) 권장 조합: 계정 잠금 + 네트워크 방어를 함께

faillock은 “계정”을 보호하지만, SSH 포트로 들어오는 시도 자체를 줄이진 못합니다.
따라서 운영에서는 보통 아래 조합이 가장 안정적입니다.

1) SSH 비밀번호 로그인 비활성화

sudo sshd -T | grep -i passwordauthentication

2) 관리망/점프서버로 SSH를 내부화

3) fail2ban 또는 nftables rate limit로 연결 노이즈 감소

4) faillock으로 계정 단위의 반복 실패 억제

계층 방어가 쌓일수록 “한 가지가 뚫려도 바로 사고로 이어지지 않는” 구조가 됩니다.

---

9) 자주 겪는 문제와 해결 단서

1) authselect 적용 후 수동으로 PAM 파일을 수정해 두어 변경이 되돌아감

- 해결: PAM 직접 편집을 피하고, authselect 기능/커스텀 프로파일로 관리

2) SSH에는 적용되는데 콘솔/ su 에서는 기대와 다름

- PAM 스택(예: system-auth, password-auth)이 서비스별로 다를 수 있음

grep -R "system-auth\|password-auth" -n /etc/pam.d | head -n 60

3) 사용자들이 자꾸 잠김

- deny를 올리거나 unlock_time을 줄이는 것만이 답이 아님
- 비밀번호 로그인 자체를 줄이고(키/MFA), 관리망으로 SSH를 옮기는 게 근본 해결

---

마무리

Rocky Linux 9에서 PAM faillock은 “계정 기반 로그인 실패 억제”를 표준화하는 좋은 방법입니다.
핵심은 authselect로 안정적으로 적용하고, deny/fail_interval/unlock_time을 운영 현실에 맞게 튜닝하며, 관리자 복구 절차를 준비하는 것입니다.

계정 잠금은 단독으로 쓰기보다
- SSH 노출 최소화
- 키 인증/인증서
- 네트워크 레이트 리밋/차단
과 함께 묶을 때 가장 효과적으로 작동합니다.