Devin.KR

원하는 구성과 현재 상태

90분 안팎

학습 목표

계정·디렉터리·유닛·방화벽 설정을 명세와 비교해 적용 계획을 출력합니다.

개념

변경 전에 무엇을 바꿀지 말할 수 있어야 합니다

작은 운영 실습실에 점검 timer까지 붙였지만, 다른 VM을 준비할 때 터미널 기록만 보고 따라 하면 설정이 달라질 수 있습니다. 설치한 순서보다 결과로 남아야 하는 계정·경로·서비스·접속 규칙이 중요합니다. 이번 레슨에서는 원하는 상태를 명세로 적고 현재 관측과 비교해 적용 계획을 만듭니다. 차이가 보인다는 이유만으로 즉시 쓰지 않습니다. 변경 대상과 영향 범위를 설명한 뒤 다음 레슨에서 그 계획을 적용합니다.

이 모듈의 실습 환경과 제출 규칙

Python 3와 bash를 사용합니다. 레슨별 starter ZIP을 새 폴더에 풀어 그 안에서 실행하고 TODO만 구현합니다. 코드 책임은 Python 함수에 두고 셸은 실행 위치와 종료 코드를 전달합니다. 앞 모듈의 bcweb·bcops·bcapp과 유한 수명 앱을 이어 사용합니다. 맥의 로컬 검사는 임시 파일과 관측 대역을 사용합니다. 실제 계정·systemd·nftables 및 소켓이 필요한 HTTP 검사는 준비된 Linux VM에서 수행하며 external로 표시합니다. 실제 VM 출력과 대역 출력을 나누어 기록합니다.

명세는 실행 명령 목록과 다릅니다

desired.json은 account의 groups, directory의 mode, unit의 user, firewall의 port를 선언합니다. 이는 실습용 비교 모델이며 실제 사용자 데이터베이스나 커널 규칙을 읽는 파일이 아닙니다. useradd를 몇 번 실행했는지가 아니라 서비스가 bcweb으로 실행되도록 선언되어 있는지가 결과입니다. 같은 명세를 적용해 같은 결과를 얻어야 구성 재현이라고 부를 수 있습니다. 패키지 버전이나 데이터 경로도 재현에 필요하면 명세의 관리 속성으로 추가합니다.

관측은 값과 조회 성공을 함께 전달합니다

current.json에는 네 대상의 현재 속성 값이 있습니다. 빈 groups 배열은 관측에 성공했지만 소속 그룹이 없는 상태입니다. 반면 대상 키가 없거나 객체 대신 null이면 관측이 누락된 것으로 취급합니다. 둘을 같게 처리하면 계정 조회 권한 오류를 계정 부재로 착각하여 새 계정을 만들 수 있습니다. 관측기에 오류가 있으면 비교를 중단하고 조회 도구·권한·대상 이름을 먼저 확인합니다. 이 실습에서는 명세의 모든 속성이 관측에 있어야 합니다.

관리 범위를 좁게 선언합니다

명세에 없는 foreign 대상과 현재 객체의 extra 속성은 비교 계획에 넣지 않습니다. 실제 서버에는 다른 담당자의 계정과 서비스가 함께 있을 수 있기 때문입니다. 현재 값에만 있다고 삭제하는 정책은 이번 과제에 없습니다. 삭제가 필요하다면 삭제 대상으로 이름과 영향, 복구 방법을 별도로 합의합니다. 선언한 필드를 관리한다는 원칙과 모든 자원을 소유한다는 주장은 구분해야 합니다. 설정 파일 전체 관리와 개별 필드 관리도 책임 범위가 다릅니다.

정렬된 차이 목록을 만듭니다

planner.py의 plan은 desired와 current 두 객체를 받으며 파일을 쓰거나 명령을 실행하지 않습니다. 대상 이름을 정렬하고 각 속성 이름도 정렬합니다. 서로 다른 값마다 resource·field·before·after를 가진 행을 추가합니다. 예를 들어 unit의 user가 root에서 bcweb으로 바뀌는 행은 실행 권한의 축소 계획입니다. 반환 배열의 순서가 일정하면 테스트와 리뷰에서 같은 차이를 쉽게 비교합니다. 시간이 필요하면 계획 함수 밖의 기록 단계에서 붙입니다.

타입 차이도 검토 대상입니다

Python에서는 True와 1의 동등 비교가 참이 될 수 있습니다. 포트나 변경 수에 논리값이 들어오면 운영 명세의 의미가 달라지므로 type을 함께 비교합니다. 권한은 이 레슨 모델에서 0750 문자열로 고정하며 다음 레슨의 파일 적용 함수에서는 정수 모드를 사용합니다. 문자열을 정수로 바꾸는 경계를 혼동하지 않습니다. 명세가 여러 표현을 허용한다면 비교 전에 정규화하고 그 정책을 테스트로 고정해야 합니다.

차이의 이유와 적용 효과를 분리합니다

directory의 0777에서 0750으로 바뀌는 계획은 접근 범위를 줄인다는 뜻입니다. 이 변경 후 bcops의 조회가 막힐지, bcweb이 데이터를 읽을 수 있을지 검토합니다. unit의 user만 맞아도 부모 디렉터리 탐색 권한이 부족하면 앱은 실패할 수 있습니다. 계획에서 한 줄이 보인다고 한 가지 영향만 있다고 생각하지 않습니다. 명세의 일치와 업무 동작 검증은 서로 다른 단계이며 실제 읽기·HTTP 확인은 변경 완료 조건에 포함합니다.

방화벽은 파일과 적용 상태가 다릅니다

모델의 firewall.port가 18089이면 비교 함수는 숫자의 차이만 보여 줍니다. 이 값은 실제 nftables가 그 포트를 허용하거나 차단했다는 증거가 아닙니다. 미션에서는 전용 inet bootcamp_m09 테이블의 규칙 구조를 커널에서 조회하고, 다른 테이블을 유지합니다. loopback에 묶인 HTTP 실습 포트를 다루며 SSH 규칙을 변경하지 않습니다. 실제 패킷 전달 검증은 앞 네트워크 모듈 기록과 연결하고 규칙 조회와 섞어 제출하지 않습니다.

계획을 검토할 때 묻는 질문

변경 행마다 대상이 맞는지, 관측이 언제 수행됐는지, 새 값의 목적은 무엇인지, 관련 자원은 어떤 순서로 준비할지 묻습니다. 앱 계정과 상위 경로가 준비되기 전에 서비스부터 기동하면 설정이 맞아도 실행은 실패할 수 있습니다. 계획은 이 의존성을 이해하는 출발점이며 자동 정렬 자체가 실행 순서를 보장하지 않습니다. 레슨 함수는 리뷰할 차이를 반환하고 미션 적용기는 경로·파일·유닛·자기 방화벽 순서로 책임을 정합니다.

따라하기에서 변경이 없다는 것을 확인합니다

solution에서 python3 -B planner.py desired.json current.json을 실행하면 네 자원의 차이가 출력됩니다. 입력 파일의 내용은 그대로 유지됩니다. 그 다음 python3 -B demo.py plan으로 user 한 필드의 간단한 예제를 확인합니다. starter에서는 차이 행 추가가 비어 있으므로 test_four_resources가 기대 4와 실제 0의 차이를 보고합니다. 원래 입력을 수정해 0으로 만들지 말고 누락된 행 추가를 완성합니다.

조회 오류를 고치는 순서

PLAN_ABORT와 종료 2가 나오면 JSON 문법과 입력 파일 경로부터 확인합니다. test_missing_observation에서 ValueError not raised가 보이면 빠진 대상·필드를 빈 객체로 대신 처리했는지 살펴봅니다. 조회 실패를 실제 없는 값으로 바꾸어 테스트를 통과시키지 않습니다. 실제 VM에서 같은 문제가 나면 getent·id·systemctl 조회 대상과 실행 권한을 확인한 뒤 새 관측으로 계획을 다시 만듭니다. 오류 원문에 비밀값이 있으면 변경 기록에 그대로 복사하지 않습니다.

VM 계정 재현은 충돌 검사부터 합니다

미션 README의 빈 VM용 계정 명령은 bcapp 그룹과 로그인 불가 bcweb·bcops를 만듭니다. 이미 있는 이름이면 반복하지 않고 id와 getent로 계약을 대조합니다. UID 번호는 환경마다 달라질 수 있으므로 숫자를 강제로 맞추지 않습니다. 기존 계정의 셸·소속이 계약과 다르면 ACCOUNT_CONFLICT 또는 GROUP_CONFLICT로 중단합니다. 공유 계정의 암호나 다른 그룹을 임의 변경하지 않고 새 명세가 기존 실습과 양립하는지 확인합니다.

완료한 계획을 다음 작업에 넘깁니다

네 차이 행과 관리하지 않는 대상, 관측 실패 시 중단 기준을 설명할 수 있으면 이번 목표를 달성한 것입니다. 제출물에는 입력 명세·관측·비교 결과와 사람이 검토한 영향이 들어갑니다. diff의 unified 문법은 더 읽기에서 확인합니다. 다음 레슨은 이 계획을 새 관측과 다시 비교한 뒤 파일을 적용하며, 같은 구성에 두 번 적용했을 때 쓰기가 발생하지 않는지 검사합니다.

미션의 전용 체인과 규칙 문법은 nftables 공식 매뉴얼에서 확인하며 실제 커널 반영은 VM에서 검증합니다.

따라하기

관리 필드만 비교

명세에 없는 현재 속성을 변경하지 않는 비교의 출발점을 확인합니다.

desired={"user":"bcweb"}
current={"user":"root","extra":"keep"}
for key in sorted(desired):
    if current[key] != desired[key]:
        print(key,current[key],"->",desired[key])

실행 결과

user root -> bcweb

차이 행의 구조 확인

solution ZIP에서 실행합니다. 이 결과는 관측 모델이며 실제 VM 상태가 아닙니다.

python3 -B demo.py plan

실행 결과

{"changes": [{"after": "bcweb", "before": "root", "field": "user", "resource": "unit"}]}

네 자원의 전체 계획 출력

같은 ZIP에서 두 입력 파일을 읽습니다. accounts·directory·unit·firewall 모델의 네 차이와 foreign 제외를 확인합니다.

python3 -B planner.py desired.json current.json

starter 비교 함수 완성

차이 행 추가 TODO를 구현하고 네 테스트가 통과하는지 확인합니다. stdout 계획과 unittest의 stderr를 구별합니다.

bash check.sh

확인 문제

실습

planner.py plan의 누락된 차이 행 추가를 구현합니다. 대상·필드를 정렬하고 before/after를 유지합니다. 관측 누락은 예외, 미관리 자원은 보존합니다. check.sh는 네 자원 차이·일치·관측 누락·타입 차이를 검사합니다. 입력 파일과 테스트는 고치지 않습니다.

시작 코드·테스트 내려받기

실행 명령

bash check.sh

기대 결과

4 tests, OK, 종료 0

모범 답안모범 답안 내려받기

더 읽기

면접 질문

  • 파일 권한 때문에 서비스가 실패하는 상황을 설명합니다.