LFCS 120분 종합 모의 실습

여러 도메인을 섞어 문제 해석, 상태 구성과 최종 검증까지 연습하는 120분 시나리오


이 문서는 LFCS 실제·복원·기출 문제가 아니다. 공개된 공식 competency를 섞어 독자적으로 만든 연습 세트다. 실제 시험과 문제 수·난이도·채점 방식이 같다고 가정하지 않는다.

작성·검증 상태: AI가 문제·풀이 구조화를 보조했다. domain을 섞는 학습용 시나리오이며 전체 세트를 동일 VM에서 end-to-end 실행한 공개 검증 기록은 아직 없다.

진행 방법

전체 120분을 다음처럼 나눈다.

0~5분    기준 상태와 대상 호스트 확인
5~105분  10개 문제 수행
105~120분 미완료 문제와 영속성·부수 효과 재검증

규칙:

  • 풀이 예시는 끝날 때까지 열지 않는다.
  • 각 문제를 대상·동작·조건·지속성·검증으로 분해한다.
  • 4분 동안 시작 방법도 찾지 못하면 표시하고 다음 문제로 이동한다.
  • 삭제·포맷·네트워크 변경 전에는 대상과 복구 경로를 확인한다.
  • 완료한 문제에는 검증 명령과 핵심 출력 한 줄을 남긴다.

실습 환경 전제

  • 검사점으로 되돌릴 수 있는 Linux VM 2대: node1, node2
  • OS와 분리된 빈 보조 디스크 1개
  • node1 콘솔 접근 가능
  • node2에는 deploy 사용자와 연습용 HTTP backend가 준비됨
  • 패키지는 배포판 기본 저장소에서 설치 가능

환경이 다르면 이름·장치·주소를 바꾸되 문제의 요구 상태는 유지한다.

문제 1. 협업 계정과 ACL — 10분

node1에서 다음 상태를 만들어라.

  • ops 그룹과 operator 사용자를 만든다.
  • operator의 기본 shell은 Bash이며 홈 디렉터리가 있어야 한다.
  • /srv/ops는 root:ops, mode 2770이다.
  • auditor 사용자는 파일을 수정하지 못하고 읽기·진입만 할 수 있다.
  • 앞으로 생성되는 항목에도 auditor의 읽기 권한이 적용돼야 한다.

검증: id, stat, getfacl, 실제 사용자 파일 생성·읽기.

풀이 방향
groupadd ops
useradd -m -s /bin/bash operator
getent passwd auditor >/dev/null || useradd -m -s /bin/bash auditor
usermod -aG ops operator
install -d -o root -g ops -m 2770 /srv/ops
setfacl -m u:auditor:rx,d:u:auditor:rx /srv/ops
runuser -u operator -- touch /srv/ops/report.txt
id operator
stat -c '%A %a %U:%G %n' /srv/ops /srv/ops/report.txt
getfacl /srv/ops /srv/ops/report.txt
runuser -u auditor -- test -r /srv/ops/report.txt && echo readable

파일의 default ACL은 실제 생성 mode와 ACL mask의 영향도 받으므로 getfacl 결과를 확인한다.

문제 2. 환경과 resource limit — 8분

operator의 새 로그인 shell에만 다음을 적용하라.

  • EDITOR=vim
  • PATH 앞에 /opt/ops/bin 추가
  • open files soft 2048, hard 4096

현재 shell이 아니라 새 session에서 결과를 확인한다.

풀이 방향

사용자 전용 환경은 홈의 login profile에 두고, limit은 PAM limits 설정에 둔다.

cat >> /home/operator/.bash_profile <<'PROFILE'
export EDITOR=vim
case ":$PATH:" in
  *:/opt/ops/bin:*) ;;
  *) export PATH="/opt/ops/bin:$PATH" ;;
esac
PROFILE
chown operator:operator /home/operator/.bash_profile
# /etc/security/limits.d/operator.conf
operator soft nofile 2048
operator hard nofile 4096
runuser -l operator -c 'printf "%s\n%s\n" "$EDITOR" "$PATH"; ulimit -Sn; ulimit -Hn'

문제 3. Git 변경 기록 — 7분

/srv/config-repo 저장소에서 다음을 수행하라.

  • 현재 변경과 branch를 확인한다.
  • service.conf만 feature/timeout branch에 commit한다.
  • notes.tmp는 commit에 포함하지 않는다.
  • main에 병합하고 최근 이력을 그래프로 확인한다.
풀이 방향
cd /srv/config-repo
git status
git diff -- service.conf
git config user.name >/dev/null || git config user.name "LFCS Lab"
git config user.email >/dev/null || git config user.email "lfcs@example.invalid"
git switch -c feature/timeout
git add service.conf
git diff --cached
git commit -m 'Adjust service timeout'
git switch main
git merge feature/timeout
git status
git log --oneline --graph -5

문제 4. custom systemd 서비스 — 12분

/usr/local/bin/write-heartbeat.sh가 15초마다 현재 시각을 출력하도록 작성하고 heartbeat.service로 관리하라.

  • operator로 실행한다.
  • 실패 시 3초 후 재시작한다.
  • 지금 실행하고 부팅 시에도 자동 시작한다.
  • unit 문법, 실행 사용자, 상태와 journal을 확인한다.
풀이 방향
cat > /usr/local/bin/write-heartbeat.sh <<'SCRIPT'
#!/bin/bash
while true; do
  echo "$(date -Is) heartbeat"
  sleep 15
done
SCRIPT
chmod 755 /usr/local/bin/write-heartbeat.sh
restorecon -v /usr/local/bin/write-heartbeat.sh
# /etc/systemd/system/heartbeat.service
[Unit]
Description=LFCS heartbeat practice

[Service]
User=operator
ExecStart=/usr/local/bin/write-heartbeat.sh
Restart=on-failure
RestartSec=3

[Install]
WantedBy=multi-user.target
systemd-analyze verify /etc/systemd/system/heartbeat.service
systemctl daemon-reload
systemctl enable --now heartbeat.service
systemctl is-enabled heartbeat.service
systemctl is-active heartbeat.service
systemctl show heartbeat.service -p User -p MainPID
journalctl -u heartbeat.service -n 5 --no-pager

문제 5. LVM과 영구 마운트 — 12분

빈 보조 디스크를 사용해 다음 상태를 만들어라.

  • VG vgdata
  • LV lvapp, 크기 1GiB
  • 파일시스템은 환경에서 지원되는 ext4 또는 XFS
  • /srv/appdata에 UUID로 영구 마운트
  • 이후 LV와 파일시스템을 512MiB 확장
풀이 방향

먼저 OS 디스크가 아닌 빈 장치를 정확히 식별한다.

lsblk -o NAME,SIZE,TYPE,FSTYPE,MOUNTPOINTS
findmnt
pvs; vgs; lvs

장치를 /dev/sdb라고 확인한 경우의 예다.

pvcreate /dev/sdb
vgcreate vgdata /dev/sdb
lvcreate -L 1G -n lvapp vgdata
mkfs.xfs /dev/vgdata/lvapp
install -d /srv/appdata
blkid /dev/vgdata/lvapp

조회한 UUID로 다음 형식의 항목을 /etc/fstab에 추가한다.

cp -a /etc/fstab /etc/fstab.before-lfcs-mixed
UUID=<조회한-UUID> /srv/appdata xfs defaults 0 0

UUID로 /etc/fstab에 추가한 뒤:

mount -a
findmnt /srv/appdata
lvextend -L +512M /dev/vgdata/lvapp
xfs_growfs /srv/appdata
lvs
df -hT /srv/appdata

ext4를 만들었다면 확장 단계에서 resize2fs /dev/vgdata/lvapp를 사용한다. pvcreate와 mkfs는 데이터를 파괴하므로 장치 확인 없이 실행하지 않는다.

문제 6. 정적 네트워크와 route — 10분

콘솔을 사용할 수 있는 격리된 실습 NIC에 다음을 영구 설정하라.

  • IPv4 192.0.2.10/24
  • gateway 192.0.2.1
  • DNS 192.0.2.53
  • 198.51.100.0/24는 192.0.2.254를 next hop으로 사용

주소, route 선택과 이름 해석 설정을 확인한다.

풀이 방향

연결 이름을 먼저 찾는다.

nmcli connection show
nmcli device status

연결 이름이 lab-static이라고 확인한 예:

nmcli connection modify lab-static \
  ipv4.method manual \
  ipv4.addresses 192.0.2.10/24 \
  ipv4.gateway 192.0.2.1 \
  ipv4.dns 192.0.2.53 \
  ipv4.route-metric 500 \
  +ipv4.routes '198.51.100.0/24 192.0.2.254'
nmcli connection up lab-static
ip -br address
ip route
ip route get 198.51.100.10
nmcli device show

원격 SSH를 제공하는 유일한 NIC에서 그대로 실행하지 않는다. 연결·장치 이름을 같다고 가정하지 않는다.

문제 7. OpenSSH 키 인증 — 10분

node1에서 node2의 deploy 사용자로 키 인증할 수 있게 하라.

  • 새 Ed25519 키를 사용한다.
  • 서버의 .ssh와 authorized_keys 권한이 안전해야 한다.
  • server 설정 문법을 검사한 뒤 reload한다.
  • 별도 session에서 키 인증과 로그를 확인한다.
풀이 방향
install -d -m 700 ~/.ssh
ssh-keyscan -t ed25519 node2 > /tmp/node2.hostkey
ssh-keygen -lf /tmp/node2.hostkey
# node2 콘솔의 `ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub` 결과와 비교한 뒤:
cat /tmp/node2.hostkey >> ~/.ssh/known_hosts
chmod 600 ~/.ssh/known_hosts
ssh-keygen -t ed25519 -f ~/.ssh/lfcs_deploy
ssh-copy-id -i ~/.ssh/lfcs_deploy.pub deploy@node2
ssh -i ~/.ssh/lfcs_deploy -o IdentitiesOnly=yes deploy@node2 id

서버에서:

namei -l /home/deploy/.ssh/authorized_keys
sshd -t
sshd -T | grep -E 'pubkeyauthentication|passwordauthentication'

구문 검사가 통과한 뒤 배포판에 맞는 service를 reload하고 로그를 확인한다.

# Rocky/RHEL
systemctl reload sshd
journalctl -u sshd -n 20 --no-pager

# Debian/Ubuntu
systemctl reload ssh
journalctl -u ssh -n 20 --no-pager

비밀번호 인증을 끄는 요구가 추가되더라도 새 키 로그인을 별도 session에서 성공시킨 뒤 기존 접근을 제한한다.

문제 8. 컨테이너와 SELinux — 12분

node1의 /srv/site/index.html을 제공하는 site 컨테이너를 실행하라.

  • 호스트 8080 → 컨테이너 80
  • bind mount의 콘텐츠가 영구적으로 남아야 함
  • SELinux Enforcing 유지
  • 컨테이너 상태, port, label, log와 실제 HTTP 응답 확인
풀이 방향
podman ps -a --filter name=site
ss -lntp | grep ':8080' || true
install -d -m 755 /srv/site
printf 'LFCS mixed lab\n' > /srv/site/index.html
podman run -d --name site -p 8080:80 \
  -v /srv/site:/usr/share/nginx/html:Z \
  docker.io/library/nginx:stable-alpine
podman ps --filter name=site
podman port site
podman inspect site
podman logs site
ls -ldZ /srv/site
curl http://127.0.0.1:8080

문제 9. 디스크 공간과 성능 진단 — 7분

/var 사용률이 높고 응답이 느리다는 신고가 들어왔다. 변경이나 삭제 없이 다음을 구분해 기록하라.

  • block 공간과 inode
  • 같은 filesystem 안의 큰 경로
  • 삭제됐지만 열린 파일
  • I/O를 많이 만드는 장치와 프로세스
풀이 방향
findmnt /var
df -hT /var
df -i /var
du -xhd1 /var | sort -h
lsof -a +L1 /var
vmstat 1 5
iostat -xz 1 5
pidstat -d 1 5

iostat·pidstat는 sysstat 패키지가 필요할 수 있다. 진단 전에 로그나 대형 파일을 삭제하지 않는다.

문제 10. 인증서와 reverse proxy — 12분

api.example.test용 private key와 CSR을 만들고 SAN을 확인하라. 이어서 미리 실행 중인 127.0.0.1:9000 backend를 Nginx가 8081에서 reverse proxy하도록 구성하라.

완료 조건

  • private key 권한은 0600이다.
  • CSR의 subject와 SAN이 올바르다.
  • key와 CSR의 public key가 일치한다.
  • backend 직접 응답과 proxy 응답을 모두 확인했다.
  • Nginx 문법 검사 뒤 reload했다.
풀이 방향
install -d -m 700 /root/lfcs-cert
cd /root/lfcs-cert
openssl req -new -newkey rsa:2048 -nodes \
  -keyout api.example.test.key \
  -out api.example.test.csr \
  -subj '/CN=api.example.test' \
  -addext 'subjectAltName=DNS:api.example.test'
chmod 600 api.example.test.key
openssl req -in api.example.test.csr -noout -text
openssl pkey -in api.example.test.key -pubout -outform DER | sha256sum
openssl req -in api.example.test.csr -pubkey -noout | \
  openssl pkey -pubin -outform DER | sha256sum

Nginx server block 핵심:

server {
    listen 8081;
    server_name api.example.test;

    location / {
        proxy_pass http://127.0.0.1:9000;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}
curl http://127.0.0.1:9000/
nginx -t
systemctl reload nginx
ss -lntp | grep ':8081'
curl -H 'Host: api.example.test' http://127.0.0.1:8081/
journalctl -u nginx -n 20 --no-pager

마지막 15분 검산

문제별로 다음을 확인한다.

검증 층질문
상태이름, 주소, 권한, 크기와 설정값이 정확한가?
동작실제 사용자·client·process로 성공하는가?
지속성새 session, service enable, fstab·connection profile에 남는가?
부수 효과기존 그룹, route, 서비스, 디스크를 바꾸지 않았는가?
systemctl --failed
findmnt --verify
ip route
ss -lntup

미완료 문제는 명령 개수보다 문제 해석·명령 탐색·설정·실행·검증 중 어디에서 막혔는지 기록한다. 그 층만 보충한 뒤 초기 상태에서 다시 120분 세트를 수행한다.

참고 자료