OpenBSD

OpenBSD는 BSD 계통의 자유·오픈 소스 유닉스 계열 운영체제이다. 1995년 NetBSD에서 분리되어 시작되었으며, 이식성과 표준 준수, 코드의 정확성, 선제적 보안, 시스템 전반에 통합된 암호화를 중심으로 개발된다. 커널만을 가리키는 이름이 아니라 커널, 기본 명령어, 시스템...

분류BSD, 유닉스 계열 운영체제, 자유 소프트웨어
개발 주체OpenBSD 프로젝트
프로젝트 책임자테오 드 라트
최초 공개1996년 7월 1일
기반NetBSD, 4.4BSD
최신 정식 버전7.9
최신 버전 공개2026년 5월 19일
구현 언어C, 어셈블리어
커널 구조모놀리식 커널
사용자 공간OpenBSD 기본 시스템
기본 셸ksh
패키지 관리pkg_add, pkg_delete, pkg_info
주요 플랫폼amd64, arm64, armv7, i386, powerpc64, riscv64 등
소스 코드 관리CVS
주요 라이선스BSD·ISC 계열 허용적 라이선스
개발 상태개발 중

OpenBSDBSD 계통의 자유·오픈 소스 유닉스 계열 운영체제이다. 1995년 NetBSD에서 분리되어 시작되었으며, 이식성과 표준 준수, 코드의 정확성, 선제적 보안, 시스템 전반에 통합된 암호화를 중심으로 개발된다. 커널만을 가리키는 이름이 아니라 커널, 기본 명령어, 시스템 라이브러리, 네트워크 서비스, 설치 도구와 문서를 하나의 프로젝트가 함께 개발하고 배포하는 완전한 운영체제다.

OpenBSD는 보안을 외부 제품이나 추가 설정으로 덧붙이는 기능보다 운영체제의 기본 설계와 개발 과정에 포함해야 할 속성으로 다룬다. 소스 코드 감사, 안전하지 않은 인터페이스의 교체, 최소 권한 원칙, 기본 서비스 축소, 권한 분리와 권한 폐기, 실행 파일 보호, 메모리 배치 무작위화 등의 기술을 시스템 전반에 적용한다. pledge, unveil, doas, malloc 보호 기능과 W^X 정책처럼 OpenBSD에서 개발되거나 적극적으로 확장된 기능은 프로그램이 접근할 수 있는 시스템 호출과 파일, 메모리 실행 권한, 관리자 권한의 범위를 줄이는 데 사용된다.

기본 시스템과 문서는 긴밀하게 관리된다. 시스템 호출, 명령어, 설정 파일과 라이브러리 인터페이스는 매뉴얼 페이지를 중심으로 문서화되며, 구현 변경과 함께 관련 문서도 수정된다. 기본 설치는 그래픽 데스크톱보다 운영체제의 핵심 기능과 네트워크 관리 도구를 제공하는 데 초점을 두지만, 포트와 바이너리 패키지를 통해 데스크톱 환경, 웹 브라우저, 개발 도구, 데이터베이스와 여러 응용 프로그램을 설치할 수 있다.

네트워크 분야에서는 패킷 필터인 PF, 경로 제어 데몬, 가상 사설망 기능, 부하 분산과 장애 조치 기능을 기본 시스템에 통합한다. OpenBSD 프로젝트는 운영체제 외에도 OpenSSH, LibreSSL, OpenBGPD, OpenSMTPD, OpenNTPD, CARP와 같은 소프트웨어와 프로토콜 구현을 개발했으며, 이 가운데 OpenSSH는 다양한 운영체제에서 원격 접속의 사실상 표준 구현으로 널리 사용된다.

OpenBSD는 약 6개월 간격으로 정식 버전을 발표하며, 정식 릴리스와 개발 브랜치인 -current, 안정화 브랜치인 -stable을 구분한다. 각 정식 릴리스는 설치 이미지와 기본 시스템 세트, 플랫폼별 패키지 저장소를 함께 제공한다. 새로운 기능의 대규모 추가보다 시스템 전체의 일관성, 코드 단순화, 오래되거나 유지하기 어려운 기능의 제거, 정확한 동작과 예측 가능한 관리 환경을 중요하게 다룬다.

역사

OpenBSD의 역사는 BSD 계통 운영체제의 발전, 인터넷을 이용한 공개 소프트웨어 개발 방식의 확산, 그리고 운영체제 보안을 설계와 개발 과정의 중심에 두려는 시도가 결합된 과정이다. OpenBSD는 처음부터 완전히 새로 작성된 운영체제가 아니라 NetBSD에서 분리되어 출발했지만, 지속적인 코드 교체와 재설계를 거치며 독자적인 커널, 사용자 공간, 보안 기술과 네트워크 소프트웨어 생태계를 구축하였다.

BSD와 NetBSD의 배경

OpenBSD의 계보는 미국 캘리포니아 대학교 버클리에서 개발된 BSD로 거슬러 올라간다. BSD는 초기 UNIX의 소스 코드를 바탕으로 발전했으며, 가상 메모리, 소켓 기반 네트워크 인터페이스, TCP/IP 구현과 여러 사용자 공간 도구를 도입하여 이후의 유닉스 계열 운영체제에 큰 영향을 주었다.

1980년대 말부터 1990년대 초까지 BSD에서 AT&T의 독점 UNIX 코드에 대한 의존성을 제거하려는 작업이 진행되었다. 그 결과 공개적으로 배포할 수 있는 Networking Release 2, 이른바 Net/2가 만들어졌으며, 이를 기반으로 인텔 80386 컴퓨터에서 실행되는 386BSD가 개발되었다. 386BSD는 일반 개인용 컴퓨터에서 사용할 수 있는 자유로운 BSD 계통 운영체제라는 의미가 있었지만, 개발과 패치 통합 속도, 프로젝트 관리 방식에 대한 불만도 나타났다.

1993년 크리스 디미트리우, 테오 드 라트, 애덤 글래스와 찰스 해넘은 386BSD와 Net/2 계통의 코드를 바탕으로 NetBSD 프로젝트를 시작하였다. NetBSD는 특정 컴퓨터 한 종류에 집중하기보다 여러 하드웨어 아키텍처에서 작동하는 이식성 높은 운영체제를 목표로 삼았다. 깨끗하고 정확한 코드, 공개된 개발 저장소, 인터넷을 통한 분산 협업도 프로젝트의 주요 방향이었다.

NetBSD의 이러한 목표는 이후 OpenBSD에도 상당 부분 이어졌다. OpenBSD가 보안을 대표적인 특징으로 발전시키기 전부터 이식성, 코드 정확성, 공개된 소스 트리와 여러 플랫폼에 대한 지원은 프로젝트의 중요한 기반이었다. OpenBSD가 공식적으로 자신을 다중 플랫폼 4.4BSD 기반 유닉스 계열 운영체제로 설명하는 것도 이러한 계보와 관련된다.[1]

OpenBSD 프로젝트의 시작

테오 드 라트는 NetBSD의 공동 창립자이자 핵심 개발자 가운데 한 명이었지만, 1994년 말 다른 핵심 개발자들과의 갈등으로 NetBSD 핵심 팀에서 물러났고 소스 코드 저장소에 대한 접근 권한도 잃었다. 당시 갈등에는 프로젝트 내부의 의사소통 방식과 개발 운영을 둘러싼 문제가 복합적으로 작용했으며, 이후 당사자들이 서로 다른 관점의 기록을 남겼다. 따라서 OpenBSD의 탄생을 단일한 기술적 견해 차이나 하나의 사건만으로 설명하기는 어렵다.

드 라트는 이후에도 NetBSD 코드를 기반으로 독자적인 개발을 계속하였고, 1995년 10월 OpenBSD 소스 코드 저장소를 만들었다. 프로젝트 이름의 Open은 소스 코드와 개발 과정에 대한 공개적 접근을 강조하는 의미를 가졌다. 당시 여러 자유 소프트웨어 프로젝트가 소스 배포본을 정기적으로 공개했지만 개발 중인 소스 저장소 전체를 인터넷에서 직접 열람할 수 있도록 운영하는 방식은 아직 일반적이지 않았다.

OpenBSD는 NetBSD 1.0 계통의 소스 트리에서 시작하였다. 초기에는 여러 부분에서 NetBSD와 공통된 코드를 사용했지만, 프로젝트는 자신의 개발 원칙에 따라 커널과 사용자 공간을 지속적으로 수정하였다. 이식성과 코드의 정확성을 유지하는 한편 라이선스가 불명확하거나 유지하기 어려운 코드, 불필요하게 복잡한 구현과 안전하지 않은 인터페이스를 정리하는 방향이 점차 분명해졌다.

1996년 7월에는 OpenBSD 1.2에 해당하는 초기 배포본이 공개되었고, 같은 해 10월 OpenBSD 2.0이 첫 정식 릴리스로 발표되었다. 이후 프로젝트는 대체로 약 6개월마다 새 정식 버전을 발표하는 개발 주기를 유지하였다. 짧고 규칙적인 릴리스 주기는 특정 기능을 장기간 별도 개발하는 방식보다 현재 소스 트리의 변경 사항을 반복적으로 통합하고 시험하는 개발 문화의 기반이 되었다.

OpenBSD는 분리 직후부터 단순한 NetBSD 변형판에 머무르지 않았다. 별도의 릴리스 체계와 패키지·포트 기반 소프트웨어 배포, 독자적인 시스템 관리 정책, 자체 매뉴얼과 보안 대응 체계를 형성하였다. 시간이 지나면서 최초 분기 당시 가져온 파일은 수정되거나 대체되었으며, OpenBSD는 같은 BSD 계보를 공유하면서도 독립적으로 발전하는 운영체제가 되었다.

초기 코드 감사와 보안 중심 개발

초기의 OpenBSD는 이식성과 코드 정확성을 주요 목표로 삼았으며, 보안은 이러한 원칙을 실제 코드 전체에 적용하는 과정에서 중심적인 위치를 차지하게 되었다. 개발자들은 특정 취약점이 발견될 때 해당 부분만 수정하는 방식에 머무르지 않고, 같은 종류의 결함이 다른 구성 요소에도 존재할 가능성을 조사하기 시작하였다.

1996년 무렵 프로젝트는 소스 트리 전반을 대상으로 체계적인 코드 감사를 진행하였다. 버퍼 경계 검사 부족, 문자열 처리 오류, 잘못된 정수 사용, 임시 파일 생성 문제, 예측 가능한 난수, 권한을 불필요하게 유지하는 데몬과 안전하지 않은 기본 설정 등이 주요 검토 대상이었다. 한 프로그램에서 발견된 오류 유형은 다른 프로그램에도 적용하여 검색되었고, 공통된 취약 패턴을 한꺼번에 제거하거나 관련 인터페이스를 교체하는 방식이 사용되었다.

이 과정에서 OpenBSD의 보안은 취약점 목록의 수동 관리보다 운영체제의 기본 구조를 바꾸는 방향으로 발전하였다. 사용자가 설치 직후 별도의 강화 작업을 하지 않아도 불필요한 네트워크 서비스가 최소화되고, 프로그램이 필요한 권한만 사용하며, 오류가 발생하더라도 피해 범위가 제한되도록 기본 구성을 설계하였다.

프로젝트는 전체 공개 원칙도 보안 개발의 일부로 채택하였다. 보안 결함이 확인되면 문제의 원인과 수정 사항을 공개하고, 소스 코드와 패치를 사용자가 직접 검토할 수 있도록 하였다. OpenBSD는 공개된 개발 모델이 상용 운영체제보다 더 적극적인 보안 변경을 가능하게 하며, 호환성을 일부 희생하더라도 위험한 인터페이스와 오래된 기능을 제거할 수 있다는 입장을 제시한다.[2]

코드 감사 과정은 안전한 문자열 함수인 strlcpystrlcat, 예측하기 어려운 난수를 간단하게 얻기 위한 arc4random, 메모리 할당기의 보호 기능과 같은 새로운 인터페이스와 구현으로 이어졌다. 이후에는 실행 가능한 메모리와 쓰기 가능한 메모리를 분리하는 W^X, 주소 공간 배치 무작위화, 스택 보호, 라이브러리 배치 무작위화, 시스템 호출 제한과 파일 시스템 접근 제한 등이 추가되었다.

OpenBSD의 보안 정책은 모든 취약점을 사전에 제거할 수 있다고 전제하지 않는다. 대신 결함이 발생할 가능성을 줄이고, 결함이 존재하더라도 공격자가 이를 안정적으로 악용하기 어렵게 하며, 침해된 프로그램이 시스템 전체에 접근하지 못하도록 여러 보호 계층을 배치하는 방향으로 발전하였다. 이러한 접근은 이후 OpenBSD의 정체성을 형성하고 다른 운영체제의 보안 기능에도 영향을 주었다. 프로젝트가 개발하거나 유지한 주요 보안 기술의 도입 시기는 공식 혁신 목록에 정리되어 있다.[3]

암호화 기술의 통합

OpenBSD는 암호화를 선택적으로 설치하는 외부 소프트웨어가 아니라 운영체제의 기본 구성 요소로 통합하려 하였다. 프로젝트가 캐나다를 중심으로 운영된 점은 당시 미국의 강한 암호화 소프트웨어 수출 규제를 피하면서 완전한 암호화 기능이 포함된 운영체제를 국제적으로 배포하는 데 유리하게 작용하였다.

1990년대에는 암호화 알고리즘과 구현 기술이 여러 국가에서 수출 규제와 소프트웨어 특허의 영향을 받았다. 미국에서 개발되어 해외로 배포되는 운영체제는 강한 암호화 기능을 제거한 별도 버전을 제공하기도 했다. OpenBSD는 암호화 코드의 개발과 통합을 캐나다에서 수행하여, 설치 후 별도 패키지를 내려받지 않아도 암호화 기능을 사용할 수 있는 시스템을 지향하였다.

암호화 통합은 로그인과 사용자 인증, 암호 저장, 가상 사설망, 네트워크 통신, 난수 생성과 저장 장치 보호 등으로 확장되었다. IPsec 지원은 운영체제 네트워크 스택에 포함되었고, 난수 생성기는 커널과 사용자 공간의 여러 보안 기능에 활용되었다. 암호화는 독립된 응용 프로그램 하나가 아니라 시스템 서비스가 공통으로 사용하는 기반 기능이 되었다.

1999년 OpenBSD 개발자들은 자유롭게 사용할 수 있는 SSH 구현을 확보하기 위해 과거의 자유 라이선스 SSH 코드와 OSSH를 바탕으로 OpenSSH를 개발하였다. 기존 SSH의 후속 버전은 사용과 재배포에 제약이 있는 라이선스로 변경되었기 때문에, OpenBSD는 코드 정리와 보안 감사를 거쳐 자유롭게 재사용할 수 있는 구현을 만들었다. OpenSSH는 1999년 12월 공개된 OpenBSD 2.6의 기본 시스템에 포함되었으며, 이후 SSH 2와 SFTP를 지원하도록 발전하였다.[4]

OpenSSH는 곧 Linux, FreeBSD와 여러 상용 UNIX를 비롯한 다른 운영체제로 이식되었다. OpenBSD 내부의 기본 구현과 다른 운영체제용 이식 계층을 분리한 개발 방식은 핵심 코드의 단순성을 유지하면서 여러 플랫폼을 지원할 수 있게 하였다. 그 결과 OpenSSH는 OpenBSD 자체의 사용 범위를 넘어 서버와 네트워크 장비에서 널리 사용되는 원격 접속 구현이 되었다.

2014년에는 Heartbleed 취약점 공개를 계기로 OpenSSL 코드베이스를 정리한 LibreSSL 프로젝트가 시작되었다. OpenBSD 개발자들은 OpenSSL을 분기한 뒤 오래된 플랫폼 지원, 사용되지 않는 기능, 복잡한 조건부 코드와 안전하지 않은 인터페이스를 제거하고 코드를 단순화하였다. LibreSSL은 OpenBSD 기본 시스템의 TLS·암호화 라이브러리가 되었으며, 다른 운영체제에서 사용할 수 있는 이식판도 제공되었다.[5]

이러한 흐름을 통해 OpenBSD는 암호화 기능을 많이 포함한 운영체제에 그치지 않고, 필요한 암호화 구현을 직접 유지하고 문제가 있는 기반 소프트웨어를 대체하는 프로젝트로 발전하였다. 통합 암호화는 이식성, 정확성, 선제적 보안과 함께 OpenBSD가 공식적으로 제시하는 핵심 목표 가운데 하나다.[6]

네트워크 운영체제로의 발전

OpenBSD는 BSD에서 이어받은 TCP/IP 네트워크 기반과 보안 중심 개발 방식을 결합하면서 방화벽, 라우터, 가상 사설망 게이트웨이와 네트워크 기반 시설에 적합한 운영체제로 발전하였다. 네트워크 기능은 외부 패키지를 조합하는 형태보다 커널, 기본 데몬, 설정 파일과 관리 명령어가 함께 개발되는 구조를 이루었다.

초기 OpenBSD는 IPFilter를 패킷 필터와 네트워크 주소 변환 기능으로 사용하였다. 그러나 2001년 IPFilter의 라이선스와 소스 변경 조건을 둘러싼 문제가 발생하자 프로젝트는 이를 기본 시스템에서 제거하고 새로운 패킷 필터를 개발하였다. 다니엘 하트마이어가 중심이 되어 개발한 PF는 같은 해 OpenBSD 3.0에 포함되었다.

PF는 패킷 필터링과 상태 추적, 네트워크 주소 변환, 트래픽 정규화, 리디렉션과 대역폭 제어를 하나의 규칙 체계에서 관리하도록 발전하였다. 규칙 문법은 관리자가 읽고 수정하기 쉬운 구성을 지향했으며, 이후 테이블, 앵커, 정책 기반 필터링, 부하 분산과 여러 네트워크 관리 기능이 추가되었다. PF는 OpenBSD의 GENERIC 커널에 포함되며 전체 개발팀이 유지한다.[7]

프로젝트는 PF 주변에 고가용성 네트워크를 구성하기 위한 기능도 구축하였다. CARP는 여러 컴퓨터가 하나의 가상 IP 주소를 공유하고 장애 발생 시 다른 컴퓨터가 역할을 넘겨받을 수 있도록 하며, pfsync는 방화벽 상태 정보를 여러 장치 사이에서 동기화한다. 이를 통해 연결 상태를 유지하는 이중화 방화벽과 라우터를 구성할 수 있게 되었다.

라우팅 분야에서는 OpenBGPD가 개발되어 BGP 기반 인터넷 라우팅을 지원하였다. OpenBGPD는 권한 분리, 읽을 수 있는 설정 형식과 작은 코드베이스를 지향하며, OpenBSD 기본 시스템과 독립적으로 이식 가능한 네트워크 데몬으로 발전하였다. 이 밖에도 OpenNTPD, OpenSMTPD, iked, relayd와 같은 서비스가 기본 시스템 또는 OpenBSD 계열 프로젝트에서 개발되었다.

OpenBSD의 네트워크 데몬은 하나의 프로세스가 모든 권한과 기능을 갖는 구조 대신 여러 프로세스로 역할을 나누는 방식을 널리 사용하였다. 외부 네트워크 입력을 해석하는 프로세스, 높은 권한이 필요한 작업을 수행하는 프로세스와 상태를 관리하는 프로세스를 분리하고, 각 프로세스가 필요한 권한만 유지하도록 설계하였다. 이러한 권한 분리 구조는 OpenSSH를 비롯한 여러 네트워크 서비스에 적용되었다.

네트워크 기능의 통합과 보수적인 기본 설정은 OpenBSD를 범용 서버 운영체제인 동시에 보안 게이트웨이와 라우팅 장비에 적합한 시스템으로 만들었다. PF와 OpenSSH를 비롯한 여러 구성 요소는 다른 BSD 계통 운영체제와 상용 제품에도 도입되면서 OpenBSD의 영향 범위를 넓혔다.

현대 OpenBSD

현대의 OpenBSD는 커널, 기본 사용자 공간, 시스템 라이브러리, 네트워크 데몬, 설치 도구와 매뉴얼 페이지를 하나의 소스 트리에서 함께 개발하는 완전한 운영체제 구조를 유지한다. Linux 배포판처럼 서로 독립적으로 개발되는 커널과 사용자 공간 구성 요소를 조합하기보다, 프로젝트가 기본 시스템 전체의 인터페이스와 동작을 일관되게 관리한다.

개발은 지속적으로 변경되는 -current 소스 트리를 중심으로 진행된다. 개발 과정에서 만들어지는 스냅샷은 새로운 기능과 수정 사항을 시험하는 데 사용되며, 일정 시점에 소스 트리를 안정화하여 정식 릴리스를 만든다. 정식 릴리스 이후에는 중요한 오류와 보안 문제를 수정한 -stable 계통과 바이너리 패치가 제공된다.

보안 개발은 초기의 소스 코드 감사에서 프로그램의 권한과 접근 범위를 직접 제한하는 구조로 확대되었다. 2015년 도입된 pledge는 프로그램이 사용할 시스템 호출의 범주를 선언하도록 하며, 선언되지 않은 동작을 시도하면 실행을 중단한다. 2018년 도입된 unveil은 프로세스가 볼 수 있는 파일과 디렉터리의 범위를 제한한다. 두 기능은 OpenBSD 기본 프로그램에 광범위하게 적용되어 프로그램이 침해되었을 때 접근할 수 있는 시스템 자원을 줄인다.

메모리 보호 역시 계속 강화되었다. W^X, 주소 공간 배치 무작위화, 위치 독립 실행 파일, 스택 보호, 라이브러리와 커널의 무작위 배치, 보호된 메모리 할당기와 제어 흐름 보호가 플랫폼별로 적용되었다. OpenBSD는 새로운 방어 기술을 추가하는 것뿐만 아니라 오래되거나 안전하게 유지하기 어려운 인터페이스를 제거하여 공격 가능한 코드와 호환성 계층의 규모를 줄이는 방식을 병행한다.

네트워크 분야에서는 PF, OpenBGPD, OpenSSH, iked와 relayd 등이 계속 발전하고 있다. 이들 프로그램은 OpenBSD 기본 시스템에서 먼저 개발되지만 일부는 다른 운영체제에서도 사용할 수 있는 이식판으로 제공된다. 특히 OpenSSH는 OpenBSD 프로젝트의 규모를 넘어 인터넷 서버, 개발 환경, 클라우드 기반 시설과 네트워크 장비에서 널리 사용되는 핵심 소프트웨어가 되었다.

하드웨어 지원에서는 amd64와 arm64를 비롯한 여러 아키텍처를 유지하며, 최신 플랫폼 지원과 기존 코드의 유지 비용을 함께 고려하여 지원 대상을 조정한다. 그래픽 환경에는 OpenBSD가 유지하는 X Window System 계통인 Xenocara가 사용되고, vmmvmd를 통한 자체 가상화 기능도 제공된다.

현대 OpenBSD의 개발 방향은 기능 수와 시장 점유율을 최대화하기보다 전체 시스템을 개발자가 이해하고 감사할 수 있는 범위로 유지하는 데 가깝다. 코드 단순화, 정확한 매뉴얼, 안전한 기본 설정, 허용적 라이선스와 일관된 기본 시스템은 초기 프로젝트에서 형성된 원칙을 현재까지 이어주는 요소다.

OpenBSD는 독립적인 운영체제로서 상대적으로 작은 사용자층을 유지하지만, 프로젝트에서 개발된 기술은 더 넓은 소프트웨어 생태계에 사용된다. OpenSSH, PF, arc4random, strlcpy, strlcat, pledge, unveil, LibreSSL과 여러 권한 분리 기법은 OpenBSD가 운영체제 보안과 네트워크 소프트웨어 개발에 미친 영향을 보여준다. 프로젝트는 현재도 이식성, 표준화, 정확성, 선제적 보안과 통합 암호화를 핵심 목표로 제시하며 개발을 계속하고 있다.[8]

프로젝트 목표와 개발 철학

OpenBSD 프로젝트는 기능의 수나 시장 점유율을 최대화하는 것보다 운영체제 전체를 자유롭게 검토하고 수정할 수 있으며, 정확하고 예측 가능하게 동작하는 상태로 유지하는 것을 우선한다. 공식적으로는 이식성, 표준화, 정확성, 선제적 보안과 통합 암호화를 핵심 목표로 제시한다.[9]

이러한 목표들은 서로 독립된 항목이 아니다. 여러 하드웨어에서 같은 코드가 동작하도록 만드는 이식성 작업은 특정 플랫폼에 숨어 있던 잘못된 가정을 드러내며, 표준 준수는 운영체제와 응용 프로그램 사이의 동작을 명확하게 만든다. 코드 단순화와 정확한 문서화는 개발자가 시스템을 검토하기 쉽게 하고, 이러한 검토 가능성은 다시 보안과 유지보수성을 높인다.

OpenBSD는 새로운 기능을 가능한 한 많이 추가하기보다 시스템 전체를 개발자가 이해하고 감사할 수 있는 규모와 구조로 유지하려 한다. 오래되었거나 중복된 코드, 안전하게 유지하기 어려운 인터페이스와 사용되지 않는 기능은 호환성을 이유로 무기한 보존하기보다 정리하거나 교체할 수 있다. 프로젝트는 이러한 지속적인 제거와 정비를 현대적인 운영체제를 유지하는 과정으로 본다.[10]

자유롭게 이용할 수 있는 소스 코드

OpenBSD의 자유 소프트웨어 정책은 소스 코드를 열람할 수 있다는 의미에만 머무르지 않는다. 프로젝트는 운영체제의 코드를 누구나 목적에 관계없이 사용하고, 복사하고, 수정하며, 배포할 수 있어야 한다는 원칙을 따른다. 이는 독점 코드와 상업적 UNIX 라이선스로부터 자유로운 BSD 배포판을 만들려 했던 버클리 Computer Systems Research Group의 전통을 계승한 것이다.[11]

OpenBSD의 기본 시스템은 주로 BSD 또는 ISC 계열의 짧고 허용적인 라이선스로 배포된다. 새로 작성되는 코드에는 일반적으로 사용·복사·수정·배포를 목적이나 유료 여부와 관계없이 허용하는 ISC 계열 문구가 권장된다. 저작권 고지와 허가 문구를 유지하는 것 외에 소스 공개나 동일 라이선스 적용을 의무화하지 않으므로, 개인과 기업은 OpenBSD 코드를 자유 소프트웨어와 독점 제품 모두에서 재사용할 수 있다.

프로젝트가 말하는 자유는 실행 파일을 무료로 받을 수 있다는 것보다 넓다. 사용자가 실행 중인 코드를 조사하고, 문제가 발생했을 때 직접 수정하며, 특정 공급자의 지원 중단이나 계약 조건에 종속되지 않는 상태를 포함한다. 이러한 이유로 OpenBSD는 소스가 제공되지 않는 커널 모듈이나 바이너리 전용 장치 드라이버를 기본 시스템에 포함하지 않는다.

장치 내부에서 실행되지만 운영체제와 직접 연결되지 않는 펌웨어는 별도로 취급된다. 재배포가 허용된 펌웨어는 fw_update를 통해 제공될 수 있지만, 커널에서 실행되는 드라이버 자체는 공개된 소스 코드로 유지한다. 이를 통해 시스템의 권한 있는 코드가 개발자와 사용자에게 검토 가능한 상태로 남도록 한다.

라이선스 조건이 소스의 자유로운 사용과 배포를 지나치게 제한하면 기술적으로 유용하더라도 기본 시스템에 포함하지 않거나 대체 구현을 개발할 수 있다. IPFilter를 제거하고 PF를 개발한 사례, 라이선스가 제한적으로 바뀐 SSH 구현을 대신하여 OpenSSH를 만든 사례는 이러한 정책이 실제 기술 개발로 이어진 경우다.

OpenBSD는 자유로운 재사용을 중요하게 여기지만 모든 자유 소프트웨어 라이선스를 동일하게 취급하지는 않는다. 기존 시스템에 포함된 일부 GPL 코드의 유지보수는 계속될 수 있으나, 프로젝트는 새로운 기본 시스템 코드에는 보다 짧고 허용적인 라이선스를 선호한다. 이는 파생 제품에 특정 배포 조건을 강제하기보다 원본 저작권 표시를 유지하면서 폭넓은 재사용을 허용하려는 방향이다.

정확성과 코드 품질

OpenBSD에서 정확성은 프로그램이 일반적인 상황에서만 작동하는 것을 뜻하지 않는다. 정상 입력과 오류 입력, 자원 부족, 하드웨어 차이, 동시 실행과 예외 상황에서도 문서에 정의된 방식으로 동작하며, 실패할 경우 예측 가능하고 안전하게 실패하는 것을 포함한다.

프로젝트는 보안 취약점을 별도의 특수한 결함으로만 보지 않는다. 경계 검사가 빠진 문자열 처리, 잘못된 정수 계산, 초기화되지 않은 메모리, 부정확한 오류 처리와 자원 누수는 처음에는 일반적인 버그로 보이더라도 이후 보안 문제로 악용될 수 있다. 따라서 코드 감사는 알려진 공격 코드를 찾기보다 기본적인 소프트웨어 오류와 잘못된 가정을 제거하는 데 초점을 둔다.[12]

한 구성 요소에서 새로운 오류 유형이 발견되면 프로젝트는 해당 파일만 수정하지 않고 소스 트리 전체에서 같은 패턴을 찾는다. 과거에 이미 감사한 코드도 새로운 취약점 유형이나 더 엄격한 검사 방법이 알려지면 다시 검토된다. 이 때문에 코드 감사는 한 번 완료되는 절차가 아니라 개발과 함께 계속되는 작업으로 취급된다.

코드의 크기와 복잡성도 정확성에 직접 영향을 주는 요소로 본다. 지나치게 많은 조건부 컴파일, 중복 구현, 오래된 플랫폼을 위한 우회 코드와 사용되지 않는 기능은 사람이 전체 동작을 이해하기 어렵게 한다. OpenBSD는 필요한 경우 코드를 제거하거나 작은 구성 요소로 다시 작성하여 검토해야 할 상태 공간을 줄인다.

기존 구현이 지나치게 복잡하거나 품질이 낮다고 판단되면 부분적인 패치보다 재작성이나 교체를 선택할 수 있다. LibreSSL은 OpenSSL 코드에서 오래된 플랫폼 지원과 불필요한 기능을 제거하며 만들어졌고, httpd, doas, smtpd와 여러 기본 데몬도 작고 감사 가능한 구현을 지향하였다.

코드 품질은 문법적 정돈만으로 판단하지 않는다. 인터페이스가 일관적인지, 오류가 호출자에게 정확히 전달되는지, 자원 소유권이 명확한지, 매뉴얼 페이지의 설명과 실제 구현이 일치하는지도 중요하게 다룬다. 문서를 작성하거나 수정하는 과정에서 구현상의 오류가 발견되는 경우도 있으므로, 문서 작업 자체가 품질 보증 과정의 일부가 된다.

OpenBSD는 기능이 많고 모든 사용 사례를 처리하는 범용 인터페이스보다 목적이 명확하고 잘못 사용하기 어려운 인터페이스를 선호한다. 완전한 일반성을 일부 포기하더라도 동작을 쉽게 이해하고 시험할 수 있다면 정확성, 보안과 사용성을 함께 높일 수 있다고 본다.

선제적 보안

OpenBSD의 선제적 보안은 취약점이 공개된 뒤 패치를 배포하는 대응형 보안보다, 아직 실제 공격에 사용되지 않은 결함과 위험한 설계 패턴을 먼저 찾아 제거하는 접근이다. 공식 프로젝트 목표에는 보안 문제에 주의를 기울이고 다른 프로젝트보다 먼저 수정하여 가장 안전한 운영체제가 되려는 방향이 명시되어 있다.[13]

이 접근은 특정 보안 제품 하나에 의존하지 않는다. 소스 코드 감사, 기본 서비스 최소화, 권한 분리, 권한 폐기, 메모리 보호, 실행 파일 무작위화, 안전한 난수 생성, 암호화와 프로그램별 자원 제한을 여러 계층에 적용한다. 하나의 방어가 우회되더라도 다른 계층이 공격의 성공 가능성과 피해 범위를 줄이도록 설계한다.

기본 설치 상태도 보안 모델의 일부다. 사용자가 직접 불필요한 서비스를 찾아 비활성화해야 하는 구조보다, 필요한 서비스만 명시적으로 켜도록 구성한다. 네트워크를 통해 접근 가능한 프로그램은 가능한 작은 권한으로 실행하며, 높은 권한이 필요한 작업은 별도의 작은 프로세스로 분리한다.

권한 분리는 복잡한 네트워크 데몬 하나를 서로 다른 역할의 프로세스로 나누는 방식이다. 외부 입력을 처리하는 프로세스가 침해되더라도 시스템 설정이나 사용자 파일에 직접 접근하지 못하게 할 수 있다. OpenSSH를 시작으로 OpenBGPD, OpenSMTPD와 여러 기본 서비스에 이러한 구조가 적용되었다.

pledge는 프로그램이 앞으로 사용할 시스템 호출의 범주를 선언하게 하며, 선언하지 않은 작업을 시도하면 실행을 중단한다. unveil은 프로세스가 볼 수 있는 파일 시스템 경로를 제한한다. 두 기능을 함께 사용하면 프로그램에 결함이 있더라도 원래 용도와 관계없는 커널 기능이나 파일에 접근하기 어렵게 만들 수 있다.

W^X는 메모리 영역이 동시에 쓰기 가능하고 실행 가능하지 않도록 하며, 주소 공간 배치 무작위화와 위치 독립 실행 파일은 공격자가 코드와 데이터의 위치를 예측하기 어렵게 한다. 스택 보호, 강화된 메모리 할당기와 제어 흐름 보호도 메모리 손상 오류가 안정적인 코드 실행으로 이어지는 것을 방해한다.

OpenBSD는 보안 문제를 가능한 한 공개적으로 다루는 전체 공개 원칙을 지지한다. 문제의 존재를 숨겨 신뢰를 유지하기보다 원인과 수정 사항을 공개하여 사용자가 위험을 이해하고 패치를 적용할 수 있게 한다. 공개 소스와 변경 기록은 외부 연구자도 수정 내용을 검토할 수 있게 한다.

선제적 보안은 완벽한 무결함을 주장하는 개념이 아니다. 결함은 계속 발견될 수 있다는 전제 아래 결함의 수를 줄이고, 악용 비용을 높이며, 침해된 구성 요소가 행사할 수 있는 권한과 접근 범위를 최소화하는 과정이다.

이식성

OpenBSD는 하나의 특정 컴퓨터를 위한 운영체제가 아니라 여러 프로세서 아키텍처와 하드웨어 플랫폼에서 동작하는 다중 플랫폼 시스템을 목표로 한다. 이식성은 NetBSD에서 이어받은 역사적 기반이지만 OpenBSD에서도 독립적인 프로젝트 목표로 유지된다.

새로운 아키텍처로 운영체제를 이식하면 코드에 숨어 있던 플랫폼 의존적 가정이 드러난다. 바이트 순서, 정수 크기, 메모리 정렬, 페이지 크기, 캐시 일관성, 장치 접근 방식과 동시성 모델이 다른 시스템에서 같은 코드를 실행하면 한 플랫폼에서는 우연히 동작하던 오류를 발견할 수 있다.

따라서 여러 아키텍처 지원은 사용자 범위를 넓히는 기능인 동시에 코드 검증 수단이다. 특정 플랫폼에서만 작성되고 시험된 코드보다 서로 다른 조건에서 컴파일되고 실행되는 코드가 자료형과 인터페이스를 더 명확하게 사용하도록 유도한다.

OpenBSD는 가능한 많은 플랫폼 이름을 유지하는 것 자체를 목표로 하지는 않는다. 유지할 개발자와 시험 장비가 부족하거나 현대적인 보안 기능을 구현하기 어려운 플랫폼은 지원 대상에서 제외될 수 있다. 이는 이식성을 명목상의 빌드 가능성보다 실제로 설치하고 유지하며 릴리스할 수 있는 상태로 정의하기 때문이다.

기계 독립 코드와 플랫폼별 코드를 분리하고, 공통 장치 계층과 일관된 커널 인터페이스를 사용하는 것도 이식성의 일부다. 특정 아키텍처의 우회 처리가 공통 코드 전체에 퍼지는 것을 줄여 새로운 플랫폼의 추가와 기존 플랫폼의 유지보수를 단순하게 만든다.

응용 프로그램 수준에서도 C와 POSIX 표준을 지키는 코드를 선호한다. 특정 컴파일러의 우연한 동작, 자료형 크기나 메모리 배치에 대한 암묵적인 가정에 의존하는 프로그램은 OpenBSD의 여러 플랫폼에서 문제를 드러낼 수 있다. 이러한 환경은 외부 소프트웨어의 이식성 오류를 찾는 데에도 사용된다.

이식성은 모든 플랫폼에서 완전히 같은 기능과 성능을 제공한다는 의미는 아니다. 장치 드라이버와 하드웨어 보안 기능은 플랫폼에 따라 다를 수 있지만, 지원되는 각 플랫폼에서 기본 시스템 전체가 일관된 빌드·설치·업그레이드 체계를 따르도록 하는 것이 핵심이다.

표준 준수와 호환성

OpenBSD는 ANSI C, POSIX와 X/Open을 비롯한 공개 표준을 추적하고 구현하는 것을 공식 목표로 삼는다.[14] 공개된 표준은 운영체제와 응용 프로그램 개발자 사이에 공통된 계약을 제공하며, 특정 공급자의 비공개 구현에 의존하지 않고 소프트웨어를 이식할 수 있게 한다.

표준 준수는 기존 동작을 그대로 복제하는 것과 구분된다. 다른 운영체제에서 널리 사용되는 비표준 동작이 있더라도 오류를 숨기거나 모호한 동작을 허용한다면 OpenBSD는 이를 따르지 않을 수 있다. 표준에 맞게 작성된 프로그램은 계속 동작하지만 잘못된 가정과 우연한 구현 세부 사항에 의존한 프로그램은 오류를 드러낼 수 있다.

시스템 헤더, C 라이브러리와 컴파일 환경은 잘못된 프로그램을 가능한 빨리 발견하도록 구성된다. 다른 환경에서 경고 없이 통과하는 소스가 OpenBSD에서 컴파일 오류나 실행 중 실패를 일으킬 수 있는데, 이는 호환성을 의도적으로 방해하기보다 정의되지 않은 동작과 잘못된 인터페이스 사용을 드러내기 위한 결과다.[15]

OpenBSD는 소스 수준 호환성을 중요하게 다루지만 다른 운영체제와의 완전한 바이너리 호환성을 최우선 목표로 두지는 않는다. 커널 내부 구조와 시스템 호출 인터페이스는 보안과 정확성을 위해 변경될 수 있으며, 오래된 호환 계층이 유지 비용과 공격 표면을 크게 늘리면 제거할 수 있다.

같은 OpenBSD 안에서도 응용 프로그램 바이너리 인터페이스가 모든 정식 릴리스 사이에서 영구적으로 유지된다고 전제하지 않는다. 기본 시스템과 패키지를 하나의 릴리스 단위로 함께 제공하고, 업그레이드할 때 운영체제와 외부 패키지를 함께 갱신하는 방식으로 전체 시스템의 일관성을 유지한다.

프로젝트는 과거와의 무조건적인 호환성보다 정확한 현재 인터페이스와 명확한 전환 절차를 선호한다. 인터페이스가 변경되면 기본 시스템의 호출자와 매뉴얼을 함께 수정하며, 포트 컬렉션을 통해 외부 소프트웨어도 새 동작에 맞게 조정한다.

이러한 정책은 일부 오래된 프로그램의 직접 실행을 어렵게 만들 수 있지만, 오랫동안 축적된 호환 코드가 핵심 시스템의 구조를 제약하는 것을 줄인다. OpenBSD에서 호환성은 모든 과거 동작을 보존하는 것이 아니라 공개 표준과 문서화된 인터페이스를 중심으로 예측 가능한 실행 환경을 제공하는 데 가깝다.

단순성과 일관성

OpenBSD가 추구하는 단순성은 기능이 적은 운영체제를 만들겠다는 의미가 아니다. 각 구성 요소가 명확한 역할을 갖고, 코드와 설정 형식이 개발자와 관리자가 이해할 수 있는 구조를 유지해야 한다는 의미에 가깝다.

프로젝트는 같은 기능을 수행하는 여러 중복 체계를 기본 시스템에 동시에 유지하기보다 하나의 일관된 구현을 선택하는 경향이 있다. 설치, 네트워크 설정, 서비스 시작, 패키지 관리와 시스템 업그레이드에는 프로젝트가 직접 관리하는 기본 도구와 설정 형식이 사용된다.

기본 시스템의 커널, 라이브러리, 명령어와 데몬은 별개의 공급자가 독립적으로 출시한 구성 요소를 조립한 것이 아니라 하나의 소스 트리에서 함께 개발된다. 한 인터페이스를 변경할 때 관련 프로그램과 문서를 같은 개발 과정에서 수정할 수 있으므로 시스템 전체의 동작을 맞추기 쉽다.

설정 파일은 일반적으로 텍스트 형식이며 사람이 읽고 검토할 수 있도록 설계된다. PF, OpenBGPD, OpenSMTPD와 doas 등의 설정 문법은 대상 분야의 개념을 직접 표현하면서도 불필요한 추상 계층과 특수한 생성 도구에 의존하지 않는 방향을 따른다.

새로운 기능을 추가할 때에는 기존 구조에 미치는 복잡성도 함께 고려한다. 기능 하나의 직접적인 가치보다 코드 크기, 유지보수 부담, 오류 가능성, 문서화 비용과 장기간 지원 가능성을 평가한다. 같은 목적을 더 작은 구현으로 달성할 수 있다면 새 의존성이나 대규모 프레임워크를 도입하지 않을 수 있다.

오래되거나 거의 사용되지 않는 기능은 유지하는 것만으로도 다른 코드를 복잡하게 만들 수 있다. OpenBSD는 이러한 코드를 제거하고 공통 경로를 단순화하는 작업을 기능 개발과 동등하게 중요하게 다룬다. 코드 제거는 지원 축소만이 아니라 남아 있는 기능의 정확성과 보안을 높이는 수단이다.

일관성은 사용자 경험에도 적용된다. 명령어의 옵션, 오류 메시지, 매뉴얼 페이지, 디렉터리 구조와 시스템 관리 방식이 서로 비슷한 원칙을 따르도록 정리한다. 사용자가 한 구성 요소에서 익힌 개념을 다른 구성 요소에도 적용할 수 있게 하여 별도의 관리 계층을 줄인다.

공개 개발과 문서화

OpenBSD의 개발은 공개된 소스 저장소, 변경 기록, 메일링 리스트와 정기적인 스냅샷을 중심으로 이루어진다. 사용자는 정식 릴리스의 결과만 받는 것이 아니라 개발 중인 -current 소스와 개별 변경 내역을 확인할 수 있다.

소스 변경은 작은 단위로 커밋되며 관련된 설명이 변경 기록에 남는다. 개발자는 메일링 리스트에서 패치와 설계를 논의하고, 다른 개발자와 사용자는 해당 변경을 시험하거나 문제를 보고할 수 있다. 공개된 과정은 특정 조직 내부에서만 검토되는 개발 방식보다 더 많은 사람이 코드와 의사 결정을 살펴볼 수 있게 한다.

공개 개발은 모든 결정을 투표나 장기간의 형식적 절차로 처리한다는 의미는 아니다. OpenBSD는 비교적 직접적인 검토와 실제 코드를 중심으로 개발하며, 충분히 시험되지 않았거나 프로젝트 방향과 맞지 않는 변경은 포함되지 않을 수 있다. 공개성은 변경이 자동으로 수용된다는 뜻보다 변경과 그 결과를 누구나 검토할 수 있다는 뜻에 가깝다.

문서화는 구현이 끝난 뒤 별도로 작성하는 부속 작업이 아니다. 시스템 호출, 라이브러리 함수, 명령어, 설정 파일과 커널 인터페이스에는 매뉴얼 페이지가 함께 제공되며, 코드 변경으로 동작이 달라지면 관련 문서도 같은 변경 과정에서 수정해야 한다.

OpenBSD의 매뉴얼은 정확하고 완전하며 간결하고 한곳에서 찾을 수 있어야 한다는 방향을 따른다. 문서의 설명이 구현과 일치하는지 확인하며, 문서를 검토하는 과정에서 코드 오류나 불명확한 인터페이스가 발견되기도 한다.[16]

기본 설치만으로 로컬 매뉴얼을 읽을 수 있으므로 네트워크 연결이나 외부 웹사이트가 없어도 시스템의 사용법과 설정 형식을 확인할 수 있다. man, apropos와 의미 기반 매뉴얼 검색 도구는 운영체제 자체가 제공하는 기본 사용자 인터페이스의 일부다.

정식 릴리스마다 변경 사항, 설치 방법, 지원 플랫폼, 오류 수정과 업그레이드 절차가 공개된다. 스냅샷과 공개된 -current 개발은 새로운 기능을 정식 릴리스 전에 넓게 시험할 수 있게 하며, 약 6개월 간격의 릴리스 과정은 개발 결과를 반복적으로 정리하고 문서화하는 기준점이 된다.

특허와 비밀 유지 계약에 대한 정책

OpenBSD는 공개적으로 검토하고 자유롭게 배포할 수 없는 기술적 의존성이 프로젝트의 개발 방식과 충돌한다고 본다. 특허, 비밀 유지 계약과 비공개 하드웨어 문서는 단순한 법률 문제가 아니라 코드 검토, 유지보수와 사용자 자유에 영향을 주는 기술적 제약으로 다룬다.

장치 제조업체가 문서를 비밀 유지 계약 아래에서만 제공하면 해당 계약에 서명한 개발자만 정보를 볼 수 있다. 다른 개발자는 코드가 하드웨어 명세를 올바르게 구현했는지 확인할 수 없고, 문제 발생 시 같은 조건에서 유지보수를 이어가기 어렵다. 이는 공개 검토를 기반으로 하는 OpenBSD의 개발 과정과 맞지 않는다.

OpenBSD의 장치 드라이버 개발 지침은 공개되었거나 합법적으로 이용할 수 있는 문서, 다른 자유 운영체제의 소스 코드와 역공학으로 확인한 정보를 사용하도록 권한다. 비밀 유지 계약은 개발자 사이에 정보 격차를 만들고 효과적인 동료 검토를 방해하므로 서명하지 않는 것이 원칙이다.[17]

프로젝트는 하드웨어 업체에 공개 문서를 제공하도록 요청하고, 문서가 없을 경우 공개적으로 확인할 수 있는 정보를 통해 장치를 지원하려 한다. 필요한 정보를 얻지 못하면 특정 장치에 대한 지원이 늦어지거나 제공되지 않을 수 있지만, 비공개 계약에 의존하여 소수 개발자만 유지할 수 있는 드라이버를 만드는 것보다 공개 개발 구조를 유지하는 쪽을 선택한다.

소프트웨어 특허에 대해서도 특정 표준이나 기능의 구현이 특허 분쟁 가능성을 만든다면 독립적인 대안을 설계할 수 있다. CARP는 고가용성 라우터 프로토콜인 VRRP와 관련된 특허 문제를 피하면서 유사한 운영 목적을 달성하기 위해 새로 설계되었다. 프로토콜 구조와 암호화된 광고 방식 등을 다르게 구성하여 독립적인 구현을 만들었다.[18]

특허나 라이선스 문제로 기존 구성 요소를 자유롭게 유지할 수 없게 되면 프로젝트는 기능을 포기하는 것 외에도 새로운 구현을 개발하는 방향을 선택한다. 이러한 제약은 PF, OpenSSH와 CARP처럼 독자적인 기술이 탄생하는 계기가 되기도 했다.

OpenBSD는 장치 지원과 기능 확대가 중요하다는 점을 인정하지만, 이를 위해 소스가 없는 바이너리 코드, 비공개 계약과 재배포를 제한하는 조건을 받아들이지는 않는다. 공식 프로젝트 자료는 이러한 타협이 사용자가 코드를 공유하고 평가하며 수정할 수 있다는 기본 목표의 일부를 포기하게 만든다고 설명한다.[19]

이 정책은 단기적으로 특정 하드웨어의 지원 범위를 제한할 수 있지만, 포함된 코드는 모든 개발자가 같은 정보에 접근하여 검토하고 수정할 수 있게 한다. 프로젝트는 하드웨어 하나를 빠르게 작동시키는 것보다 운영체제 전체가 장기적으로 자유롭고 감사 가능한 상태를 유지하는 것을 우선한다.

시스템 구성

OpenBSD는 커널, 시스템 라이브러리, 기본 명령어, 네트워크 데몬, 설치 도구와 매뉴얼을 하나의 프로젝트에서 함께 개발하는 완전한 운영체제다. Linux 배포판처럼 서로 독립된 여러 프로젝트의 구성 요소를 조합하여 기본 운영체제를 만드는 방식과 달리, OpenBSD 프로젝트가 기본 시스템 전체의 소스 코드와 인터페이스를 통합하여 관리한다.

OpenBSD의 소프트웨어 환경은 크게 기본 시스템외부 소프트웨어로 구분된다. 기본 시스템은 정식 릴리스의 파일 세트로 설치되며 커널, 사용자 공간 도구, 시스템 라이브러리와 문서를 포함한다. 웹 브라우저, 데스크톱 환경, 데이터베이스, 추가 프로그래밍 언어와 같은 제3자 프로그램은 포트와 바이너리 패키지로 제공된다.

이 구분은 단순한 설치 방식의 차이가 아니다. 기본 시스템은 OpenBSD 프로젝트의 코드 감사와 릴리스 정책 아래에서 하나의 운영체제로 관리되지만, 포트와 패키지에 포함된 제3자 소프트웨어 전체에는 기본 시스템과 같은 수준의 보안 감사를 적용할 수 없다. 따라서 OpenBSD의 보안성과 일관성을 설명할 때에는 기본 시스템과 추가 패키지를 구분할 필요가 있다.[20]

기본 시스템

OpenBSD의 기본 시스템은 시스템을 부팅하고 관리하며 개발과 네트워크 서비스를 수행하는 데 필요한 핵심 구성 요소의 집합이다. 커널만을 의미하지 않으며, 커널과 함께 동작하도록 개발된 사용자 공간 프로그램, 시스템 라이브러리, 헤더 파일, 설정 도구와 매뉴얼 페이지를 포함한다.

기본 시스템은 OpenBSD 소스 트리의 src 계통에서 함께 개발된다. 커널 인터페이스가 변경되면 관련 사용자 공간 프로그램과 라이브러리, 시스템 헤더와 매뉴얼도 같은 소스 트리 안에서 조정된다. 이러한 구조는 운영체제 구성 요소 사이의 버전과 인터페이스를 프로젝트가 직접 맞출 수 있게 한다.

정식 릴리스는 기능에 따라 여러 설치 파일 세트로 나누어 배포된다. 일반적으로 baseXX.tgz에는 필수 사용자 공간 파일, compXX.tgz에는 컴파일러와 개발 파일, manXX.tgz에는 매뉴얼 페이지가 들어간다. X Window System을 위한 실행 파일, 라이브러리, 글꼴과 서버도 별도의 파일 세트로 제공된다. 여기서 XX는 릴리스 번호를 나타낸다.

커널은 파일 시스템 최상위의 /bsd에 설치되며, 설치와 복구에 사용하는 램디스크 커널은 /bsd.rd에 위치한다. /bsd.booted가 존재하는 시스템에서는 현재 부팅된 커널을 가리키는 데 사용될 수 있다. 정식 업그레이드와 sysupgrade는 커널과 기본 시스템 파일 세트를 함께 갱신한다.

기본 시스템 파일 세트는 패키지가 아니다. baseXX.tgzcompXX.tgzpkg_add로 설치하거나 관리하지 않으며, 운영체제 설치·업그레이드 절차를 통해 배치된다. 반대로 /usr/local 아래에 설치되는 일반적인 제3자 소프트웨어는 패키지 데이터베이스를 통해 관리된다.[21]

기본 시스템의 많은 네트워크 기능도 별도 패키지가 아닌 운영체제의 일부다. PF, OpenSSH, OpenBGPD, OpenNTPD, httpd, relayd, iked와 여러 관리 도구가 기본 소스 트리에서 개발된다. 따라서 해당 구성 요소는 커널과 시스템 라이브러리의 변화에 맞춰 함께 수정되고 정식 릴리스의 일부로 시험된다.

OpenBSD는 기본 시스템이 자체적으로 충분히 사용할 수 있는 운영체제가 되도록 구성한다. 외부 패키지를 하나도 설치하지 않아도 파일 관리, 네트워크 설정, 방화벽, 원격 접속, 소프트웨어 개발, 시스템 진단과 서버 운영에 필요한 기본 도구를 사용할 수 있다. 포트와 패키지는 이 기반을 대체하지 않고 추가 기능을 제공한다.[22]

커널

OpenBSD 커널은 프로세스 실행, 가상 메모리, 파일 시스템, 네트워크, 장치 입출력과 보안 정책을 관리한다. 전통적인 BSD 계통의 모놀리식 커널 구조를 사용하며, 주요 커널 서비스와 장치 드라이버가 하나의 권한 영역에서 동작한다.

OpenBSD는 일반 사용자가 프로젝트에서 제공하는 GENERIC 또는 플랫폼에 따라 GENERIC.MP 커널을 그대로 사용하는 것을 권장한다. 이 커널은 지원 플랫폼에서 정식으로 빌드되고 시험되며, 일반적인 장치 드라이버와 시스템 기능을 포함한다. 사용자가 기능을 임의로 제거한 커스텀 커널은 프로젝트가 동일한 조건으로 시험하기 어렵기 때문에 일반적인 관리 방식으로 권장되지 않는다.[23]

커널 이미지는 일반적으로 /bsd에 저장된다. /bsd.rd는 파일 시스템 안에 소형 사용자 공간을 포함한 램디스크 커널로, 설치 프로그램과 업그레이드, 제한적인 복구 환경을 실행하는 데 사용된다. 일부 플랫폼에서는 부팅 과정에 필요한 추가 커널 이미지나 부트 로더도 사용한다.

커널은 사용자 공간 프로그램에 시스템 호출 인터페이스를 제공한다. 프로세스 생성, 파일 열기, 메모리 매핑, 네트워크 통신과 권한 제어는 시스템 호출을 통해 요청된다. pledgeunveil 같은 OpenBSD 보안 인터페이스도 사용자 공간 프로그램이 커널에 자신의 허용 작업 범위를 전달하는 방식으로 동작한다.

네트워크 스택과 PF 역시 커널에 포함된다. 패킷 수신과 전송, 라우팅, 소켓, 상태 기반 필터링, 네트워크 주소 변환과 여러 가상 네트워크 인터페이스가 커널 수준에서 처리된다. 사용자 공간의 pfctl, ifconfig, route와 네트워크 데몬은 이러한 커널 기능을 설정하고 관리한다.

OpenBSD 커널은 전통적인 적재 가능 커널 모듈에 의존하지 않는다. 커널에서 높은 권한으로 실행되는 코드는 정식 소스 트리와 빌드 과정 안에서 관리하는 방향을 따른다. 바이너리 전용 커널 드라이버를 설치하여 커널 기능을 확장하는 방식도 제공하지 않는다.

커널 구성은 플랫폼별 설정 파일과 장치 정의를 통해 빌드 시 결정된다. 장치는 버스와 상위 장치에 연결되는 계층적인 트리로 표현되며, 각 드라이버는 지원하는 상위 장치 또는 버스에 부착된다.[24]

사용자 공간

사용자 공간은 커널 바깥에서 실행되는 명령어, 셸, 시스템 데몬, 개발 도구와 응용 프로그램의 실행 환경이다. 일반 프로그램은 하드웨어와 커널 메모리에 직접 접근하지 않고 시스템 호출과 시스템 라이브러리를 통해 운영체제 기능을 사용한다.

OpenBSD의 기본 사용자 공간에는 파일과 디렉터리 관리, 프로세스 제어, 텍스트 처리, 네트워크 설정, 사용자 관리, 시스템 진단과 소프트웨어 빌드를 위한 도구가 포함된다. ls, cp, mv, ps, grep, awk, sed, make, cc, ssh, ftp, ifconfig와 같은 프로그램이 대표적이다.

시스템 데몬도 기본 사용자 공간의 일부다. 부팅과 서비스 관리를 담당하는 initrc, 보안 셸 서비스를 제공하는 sshd, 시스템 로그를 처리하는 syslogd, 시간 동기화를 수행하는 ntpd, 라우팅 프로토콜을 구현하는 bgpd 등이 커널 위에서 별도 프로세스로 실행된다.

OpenBSD는 높은 권한이 필요한 기능과 외부 입력을 처리하는 기능을 하나의 프로세스에 집중시키지 않으려 한다. 여러 데몬은 권한 분리 구조를 사용하여 네트워크 입력 해석, 상태 관리와 시스템 변경을 서로 다른 프로세스로 나눈다. 작업을 시작한 뒤 더 이상 필요하지 않은 권한과 파일 접근 범위를 제거하는 방식도 사용한다.

기본 사용자 공간 프로그램에는 pledgeunveil이 폭넓게 적용된다. 각 프로그램은 자신의 역할에 필요한 시스템 호출과 파일만 접근할 수 있도록 제한되며, 프로그램 내부의 오류가 시스템 전체에 대한 접근으로 확대되는 것을 줄인다.

OpenBSD의 기본 사용자 공간과 외부 패키지는 일반적으로 설치 위치도 구분된다. 기본 시스템의 실행 파일은 /bin, /sbin, /usr/bin, /usr/sbin 등에 배치되고, 패키지로 설치한 프로그램은 주로 /usr/local/bin, /usr/local/sbin, /usr/local/lib/usr/local/share 아래에 배치된다. 이 구조는 운영체제 파일과 관리자가 추가한 소프트웨어를 구분하기 쉽게 한다.[25]

시스템 라이브러리

시스템 라이브러리는 사용자 공간 프로그램이 커널과 운영체제 기능을 사용할 수 있도록 공통 인터페이스를 제공한다. C 표준 라이브러리, 시스템 호출 래퍼, 암호화, 스레드, 수학, 장치와 네트워크 관련 라이브러리가 기본 시스템에 포함된다.

가장 기본적인 구성 요소는 C 라이브러리인 libc다. 문자열과 메모리 처리, 파일 입출력, 프로세스 제어, 사용자와 그룹 정보, 소켓, 이름 해석과 시간 처리 등 대부분의 C 프로그램이 사용하는 기능을 제공한다. 시스템 호출도 일반적으로 libc의 함수 인터페이스를 통해 사용된다.

OpenBSD는 안전하게 사용하기 쉬운 라이브러리 인터페이스를 직접 개발하거나 확장해 왔다. 크기가 제한된 문자열 복사를 위한 strlcpystrlcat, 편향을 피하는 범위 난수 함수 arc4random_uniform, 명시적으로 지워져야 하는 메모리를 위한 explicit_bzero 등이 기본 라이브러리에 포함된다.

TLS와 일반 암호화 기능은 LibreSSL 계통의 libssl, libcrypto와 관련 라이브러리를 통해 제공된다. OpenSSH, httpd, ftp와 여러 시스템 프로그램은 이러한 기반을 사용한다. 암호화 라이브러리는 별도의 선택적 패키지가 아니라 기본 운영체제와 함께 관리된다.

스레드 기능은 POSIX 스레드 인터페이스를 제공하는 라이브러리를 통해 사용한다. 동적 실행 파일은 런타임 링커가 필요한 공유 라이브러리를 적재하며, 프로그램과 라이브러리의 주소는 시스템 보안 정책에 따라 무작위화될 수 있다.

기본 시스템 라이브러리는 주로 /usr/lib에 위치하고, 관련 헤더는 /usr/include에 설치된다. 패키지에서 설치한 외부 라이브러리와 헤더는 일반적으로 /usr/local/lib/usr/local/include에 위치한다. 이러한 분리는 기본 시스템의 라이브러리가 외부 프로그램 설치 과정에서 임의로 대체되는 것을 방지한다.

OpenBSD는 정식 릴리스 사이의 무제한적인 바이너리 호환성을 기본 전제로 삼지 않는다. 기본 시스템과 패키지는 해당 릴리스 또는 스냅샷에 맞춰 함께 빌드되며, 시스템을 업그레이드한 뒤에는 설치된 패키지도 대응하는 저장소의 버전으로 갱신해야 한다.

명령줄 환경

OpenBSD의 기본 관리 환경은 명령줄을 중심으로 구성된다. 설치, 네트워크 설정, 서비스 관리, 패키지 설치와 시스템 진단을 기본 명령어와 텍스트 설정 파일을 통해 수행할 수 있다.

기본 사용자 셸은 공개 도메인 KornShell을 기반으로 한 ksh다. sh로 실행되는 시스템 스크립트와 대화형 사용자 셸을 모두 지원하며 명령 기록, 작업 제어, 별칭, 함수와 명령줄 편집 기능을 제공한다. 기본 시스템에는 C 셸 계열의 csh도 포함될 수 있고, Bash·Zsh·Fish와 같은 다른 셸은 패키지로 설치할 수 있다.[26]

관리자 권한이 필요한 명령은 root 계정으로 직접 로그인하거나 doas를 통해 실행할 수 있다. doas는 허용된 사용자와 명령을 /etc/doas.conf에 간결하게 정의하며, 복잡한 권한 위임 체계보다 작은 코드와 명확한 규칙을 지향한다.

시스템 서비스는 rcctl을 통해 활성화, 비활성화, 시작, 중지하고 상태를 확인할 수 있다. rcctl/etc/rc.conf.local과 패키지 서비스 설정을 관리하며, 사용자가 부팅 스크립트를 직접 수정하지 않고도 서비스 구성을 변경할 수 있게 한다.

네트워크는 ifconfig, route, netstat, pfctl과 여러 전용 명령으로 관리한다. 영구 설정은 /etc/hostname.if, /etc/mygate, /etc/resolv.conf, /etc/pf.conf 등의 파일에 기록된다. 현재 실행 상태를 바꾸는 명령과 다음 부팅에도 적용될 설정 파일이 명확하게 구분된다.

기본 텍스트 편집기로는 vi 계열 편집기가 제공되며, 간단한 파일 수정에는 ed도 사용할 수 있다. Emacs, Vim, Neovim과 그래픽 편집기는 패키지 시스템을 통해 추가할 수 있다.

명령줄 도구는 매뉴얼 페이지와 직접 연결된다. 명령의 이름을 알고 있으면 man 명령어로 사용법을 확인할 수 있고, 정확한 명령을 모르면 apropos로 매뉴얼 설명을 검색할 수 있다. 이 구조는 외부 관리 프로그램 없이도 시스템 자체에서 사용 방법을 찾을 수 있게 한다.

장치 드라이버

장치 드라이버는 커널이 하드웨어를 인식하고 제어할 수 있도록 하는 구성 요소다. 프로세서와 시스템 버스, 저장 장치, 네트워크 어댑터, 그래픽 장치, 오디오 장치, USB 주변기기와 센서 등이 드라이버를 통해 커널의 공통 인터페이스에 연결된다.

OpenBSD는 장치의 일반적인 종류보다 실제 드라이버 이름을 중심으로 장치를 명명한다. 예를 들어 인텔 PRO/1000 계열 네트워크 장치는 em0, Broadcom 계열 장치는 bge0처럼 표시될 수 있다. 같은 종류의 장치라도 사용되는 드라이버가 다르면 인터페이스 이름도 달라진다.[27]

장치 번호는 부팅 시 발견된 순서와 장치 연결 구조에 따라 붙는다. sd0, sd1과 같은 저장 장치 이름도 특정 물리적 연결 방식을 직접 의미하기보다 SCSI 계층을 사용하는 디스크 드라이버와 발견 순서를 나타낸다.

커널은 장치를 계층적인 트리로 구성한다. 프로세서 또는 시스템 버스 아래에 PCI나 USB 컨트롤러가 연결되고, 그 아래에 개별 장치와 논리 인터페이스가 부착된다. 부팅 메시지와 dmesg를 통해 어떤 장치가 어떤 드라이버에 연결되었는지 확인할 수 있다.

드라이버는 OpenBSD 소스 트리 안에서 공개된 코드로 유지된다. 프로젝트는 커널 내부에서 실행되는 바이너리 전용 드라이버를 지원하지 않으며, 하드웨어 문서가 공개되지 않은 경우 공개된 자료나 합법적인 역공학을 통해 드라이버를 개발한다.

일부 무선 네트워크 장치와 그래픽 장치는 장치 자체에서 실행되는 펌웨어가 필요하다. 재배포가 허용된 펌웨어는 fw_update를 통해 내려받을 수 있다. 펌웨어는 장치 내부 프로세서에서 실행되므로, 운영체제 커널 안에서 실행되는 소스 비공개 드라이버와는 구분된다.

OpenBSD는 개별 장치용 드라이버뿐 아니라 가상 장치도 폭넓게 사용한다. lo, bridge, trunk, vlan, vether, tun, tap, wg, enc와 같은 네트워크 인터페이스는 물리적 장치와 결합하여 라우팅, 가상 사설망, 장애 조치와 네트워크 가상화를 구성한다.

하드웨어 지원 범위는 플랫폼과 릴리스에 따라 달라진다. 새로운 장치는 공개된 문서, 개발 장비와 유지보수할 개발자가 있을 때 지원될 수 있으며, 오래되어 시험이 불가능하거나 유지 비용이 큰 장치는 이후 지원 대상에서 제외될 수 있다.

설정 파일

OpenBSD의 시스템 설정은 주로 /etc 아래의 일반 텍스트 파일로 관리된다. 설정을 생성하는 중앙 데이터베이스나 특정 그래픽 관리 도구에 의존하기보다, 각 서비스와 시스템 구성 요소가 자신의 문서화된 설정 파일을 읽는 구조를 사용한다.

네트워크 인터페이스의 영구 설정은 /etc/hostname.if 형식의 파일에 저장한다. 여기서 if는 실제 인터페이스 이름으로 대체되므로 em0의 설정은 /etc/hostname.em0, 무선 장치 iwx0의 설정은 /etc/hostname.iwx0에 기록된다.

PF 규칙은 /etc/pf.conf, DNS 해석기 설정은 /etc/resolv.conf, 기본 게이트웨이 관련 정보는 네트워크 설정 파일에 기록된다. OpenSSH 서버는 /etc/ssh/sshd_config, 시간 동기화는 /etc/ntpd.conf, BGP 라우팅은 /etc/bgpd.conf처럼 각 데몬이 독립적인 설정 파일을 사용한다.

시스템 서비스의 활성화와 시작 옵션은 /etc/rc.conf.local에서 관리한다. 기본값은 시스템이 제공하는 /etc/rc.conf에 정의되지만, 관리자는 원본 파일을 직접 수정하기보다 rcctl을 통해 로컬 변경 사항을 기록하는 방식을 사용한다.

사용자 계정과 인증 관련 정보는 /etc/passwd, /etc/master.passwd, /etc/group, 로그인 클래스는 /etc/login.conf에 저장된다. 직접 편집할 때에는 파일 형식과 데이터베이스 갱신을 처리하는 vipw, chpass, useradd, usermod 등의 전용 도구를 사용하는 것이 일반적이다.

패키지로 설치한 서비스의 예제 설정은 주로 /usr/local/share/examples에 제공되고, 실제 설정은 /etc 또는 /etc 아래의 전용 디렉터리에 설치될 수 있다. 패키지 시스템은 관리자가 수정한 설정 파일을 업그레이드 과정에서 무조건 덮어쓰지 않도록 샘플 파일과 실제 설정을 구분한다.

정식 시스템 업그레이드 뒤에는 sysmerge/etc/var에 있는 시스템 설정 파일의 변경 사항을 병합한다. 자동으로 처리할 수 있는 변경은 적용하고, 관리자의 로컬 수정과 충돌하는 부분은 비교하여 선택할 수 있도록 한다.

각 설정 파일의 문법은 같은 이름의 매뉴얼 페이지 5절에 문서화되는 경우가 많다. 예를 들어 pf.conf(5), sshd_config(5), hostname.if(5)doas.conf(5)에서 파일 형식과 사용 가능한 지시어를 확인할 수 있다.

매뉴얼 페이지

매뉴얼 페이지는 OpenBSD의 공식 시스템 문서이며 명령어, 시스템 호출, 라이브러리 함수, 장치 드라이버, 설정 파일과 커널 내부 인터페이스를 설명한다. FAQ와 웹 문서는 보충 자료로 사용되지만, 기본적인 사용법과 인터페이스의 기준은 매뉴얼 페이지다.

OpenBSD 개발자는 시스템 코드를 변경할 때 관련 매뉴얼 페이지도 함께 갱신해야 한다. 구현과 문서를 별도 작업으로 분리하지 않기 때문에 새 기능이나 인터페이스 변경이 코드에 포함될 때 사용법과 동작 설명도 같은 개발 과정에서 검토된다.[28]

매뉴얼은 주제에 따라 절로 구분된다. 1절은 일반 사용자 명령, 2절은 시스템 호출, 3절은 라이브러리 함수, 4절은 장치와 장치 드라이버, 5절은 파일 형식, 7절은 일반 정보, 8절은 시스템 관리 명령, 9절은 커널 개발 인터페이스를 주로 다룬다.[29]

명령 이름을 알고 있다면 man 이름으로 문서를 열 수 있다. 같은 이름이 여러 절에 존재하면 man 5 이름처럼 절 번호를 지정할 수 있다. 키워드나 설명으로 문서를 찾을 때에는 apropos 또는 man -k를 사용한다.

매뉴얼 원문은 정식 설치의 manXX.tgz 파일 세트에 포함되며 일반적으로 /usr/share/man에 설치된다. 패키지에서 제공하는 매뉴얼은 주로 /usr/local/man에 배치된다. 따라서 인터넷 연결이 없어도 설치된 운영체제와 패키지의 문서를 로컬에서 읽을 수 있다.

매뉴얼 페이지는 명령 옵션을 나열하는 데 그치지 않고 반환값, 오류 조건, 설정 예시, 관련 파일, 표준 준수 여부와 역사도 설명할 수 있다. 시스템 호출과 라이브러리 함수의 매뉴얼은 프로그램이 어떤 상황에서 실패하며 어떤 오류 번호를 반환하는지도 정의한다.

모든 OpenBSD 매뉴얼은 man.openbsd.org에서도 제공된다. 웹 버전은 정식 릴리스와 -current 문서를 선택하여 볼 수 있으므로, 서로 다른 버전의 인터페이스와 설정을 비교하는 데에도 사용할 수 있다.

포트와 패키지

OpenBSD의 포트와 패키지는 기본 시스템에 포함되지 않은 제3자 소프트웨어를 설치하기 위한 체계다. 두 개념은 서로 다른 소프트웨어 저장소가 아니라, 같은 외부 소프트웨어를 소스에서 빌드하는 과정과 그 결과로 만들어진 바이너리 배포물을 가리킨다.

포트 컬렉션은 각 프로그램의 원본 소스를 어디에서 내려받고, 어떤 패치를 적용하며, 어떻게 구성·컴파일·시험하고 패키지로 만들지를 정의하는 Makefile과 메타데이터의 집합이다. 기본 위치는 /usr/ports이며 분야별 디렉터리 아래에 개별 포트가 배치된다.[30]

각 포트에는 일반적으로 빌드 규칙을 담은 Makefile, 배포 파일의 크기와 체크섬을 기록한 distinfo, 패키지 설명인 DESCR, 설치될 파일 목록인 PLIST가 포함된다. 필요한 경우 OpenBSD에서 동작하도록 원본 소스를 수정하는 패치도 함께 제공한다.

포트는 하나의 소스 코드에서 여러 바이너리 패키지를 만들 수 있다. 기능 집합이 다른 flavor를 제공하거나 프로그램 본체, 문서, 라이브러리와 추가 모듈을 여러 subpackage로 나눌 수 있다. 이를 통해 사용자는 필요한 구성 요소만 설치할 수 있다.

일반 사용자는 포트에서 직접 컴파일하기보다 공식 미러에서 제공하는 사전 빌드 바이너리 패키지를 사용하는 것이 권장된다. OpenBSD 포트 팀은 포트 자체보다 설치 가능한 패키지를 포팅 작업의 최종 결과로 본다.[31]

패키지는 pkg_add로 설치하고 갱신하며, pkg_delete로 제거하고 pkg_info로 정보를 확인한다. pkg_check는 설치된 패키지 데이터베이스와 파일의 일관성을 검사하는 데 사용한다. 패키지 저장소의 기본 주소는 /etc/installurl을 기준으로 결정된다.

pkg_add는 필요한 의존 패키지를 자동으로 검색해 먼저 설치하고, 파일 충돌과 기존 설치 여부를 확인한다. 설치된 패키지 정보는 기본적으로 /var/db/pkg에 기록되며, 다른 프로그램이 사용 중인 의존성을 실수로 제거하지 않도록 관계를 추적한다.[32]

공식 패키지는 서명되어 배포되며, pkg_add는 압축을 해제하기 전에 서명과 패키지 데이터가 일치하는지 검증한다. 서명은 전송 과정이나 미러에서 패키지가 변조되지 않았음을 확인하지만, 패키지에 포함된 제3자 프로그램 자체가 보안 결함이 없음을 보증하는 것은 아니다.[33]

패키지로 설치된 실행 파일과 라이브러리는 주로 /usr/local 아래에 배치된다. 사용자 명령은 /usr/local/bin, 관리 명령은 /usr/local/sbin, 라이브러리는 /usr/local/lib, 공유 데이터는 /usr/local/share에 설치된다. 이 방식은 기본 시스템 파일과 외부 소프트웨어가 서로 섞이는 것을 줄인다.

포트와 패키지는 사용 중인 OpenBSD 릴리스와 일치해야 한다. 정식 릴리스 시스템은 해당 릴리스용 패키지를 사용하고, -current 스냅샷은 대응하는 스냅샷 패키지와 함께 갱신해야 한다. 기본 시스템만 새 버전으로 올리고 오래된 패키지를 그대로 사용하면 라이브러리와 인터페이스가 맞지 않을 수 있다.

OpenBSD 기본 시스템은 프로젝트의 집중적인 코드 감사 대상이지만, 수많은 외부 프로그램으로 구성된 포트와 패키지 전체에는 같은 수준의 감사를 적용할 수 없다. 포트 인프라는 프로그램을 OpenBSD에 맞게 빌드하고 관리 가능한 패키지로 제공하지만, 외부 소프트웨어의 코드 품질과 보안 특성이 OpenBSD 기본 시스템과 동일하다는 의미는 아니다.[34]

커널 구조

OpenBSD 커널은 프로세스와 메모리, 파일 시스템, 장치, 네트워크와 보안 정책을 하나의 커널 주소 공간에서 관리하는 모놀리식 커널이다. 전통적인 BSD 커널 구조를 계승하지만, 다중 프로세서 환경을 위한 세분화된 잠금, 가상 메모리 체계인 UVM, 가상 파일 시스템 계층, 플랫폼 독립적인 장치 접근 인터페이스와 여러 보안 완화 기술을 지속적으로 통합해 왔다.

커널의 공통 기능은 여러 하드웨어 아키텍처에서 공유되는 기계 독립 코드와 각 프로세서·플랫폼에 맞춘 기계 의존 코드로 나뉜다. 프로세스 관리, 네트워크 스택과 파일 시스템의 상당 부분은 공통 코드로 구현되고, 부팅, 페이지 테이블, 인터럽트 제어, 문맥 전환과 장치 버스 접근처럼 하드웨어에 직접 의존하는 부분은 아키텍처별 구현이 담당한다.

OpenBSD 커널은 기능을 독립 서버로 분리하는 마이크로커널 구조를 사용하지 않는다. 대신 커널 내부의 하위 시스템 사이에 명확한 인터페이스와 동기화 규칙을 두고, 사용자 공간 프로그램은 시스템 호출을 통해서만 커널 자원에 접근한다. 커널의 내부 구조는 intro(9)를 시작으로 프로세스, 메모리, 파일 시스템과 장치 인터페이스에 관한 개발자 매뉴얼에 문서화되어 있다.[35]

모놀리식 커널

OpenBSD는 프로세스 스케줄러, 가상 메모리, 파일 시스템, 네트워크 스택과 장치 드라이버가 커널 공간에서 함께 실행되는 모놀리식 커널 구조를 사용한다. 이러한 구성 요소들은 사용자 공간 프로그램보다 높은 권한으로 실행되며 서로 직접 함수를 호출하고 공통 커널 자료구조를 사용할 수 있다.

모놀리식 구조는 파일 시스템이나 네트워크 패킷 처리처럼 여러 하위 시스템이 긴밀하게 협력해야 하는 작업에서 추가적인 프로세스 간 통신 없이 기능을 연결할 수 있게 한다. 시스템 호출로 들어온 요청은 커널 내부에서 필요한 하위 시스템으로 전달되고, 처리 결과가 다시 사용자 공간으로 반환된다.

OpenBSD 커널은 전통적인 적재 가능 커널 모듈을 일반적인 확장 방식으로 제공하지 않는다. 장치 드라이버와 주요 커널 기능은 정식 소스 트리에 포함되어 커널과 함께 빌드된다. 이 구조는 실행 중인 커널에 임의의 바이너리 코드를 삽입하는 경로를 줄이고, 커널 내부 코드가 프로젝트의 빌드와 검토 과정 안에 남도록 한다.

일반 설치에서는 프로젝트가 제공하는 GENERIC 또는 다중 프로세서용 GENERIC.MP 계열 커널이 사용된다. 이 커널에는 해당 플랫폼에서 일반적으로 필요한 장치 드라이버와 기능이 포함되며, 정식 릴리스와 스냅샷에서 반복적으로 빌드되고 시험된다.

모놀리식이라는 표현이 모든 커널 코드가 하나의 거대한 절차로 구성된다는 의미는 아니다. OpenBSD 내부에는 UVM, VFS, 네트워크 스택, 장치 구성 체계와 플랫폼별 기계 의존 계층이 존재하며, 각 하위 시스템은 정해진 자료구조와 호출 인터페이스를 통해 연결된다.

커널 내부 오류는 전체 시스템에 영향을 줄 수 있으므로 OpenBSD는 커널 코드의 크기와 복잡성을 줄이고, 장치 드라이버와 공통 코드를 공개된 소스 트리에서 함께 검토하는 방식을 취한다. 사용자 공간으로 옮길 수 있는 복잡한 정책과 외부 입력 처리는 가능한 경우 권한이 제한된 사용자 공간 프로세스가 담당하도록 설계된다.

프로세스와 스레드

OpenBSD에서 프로세스는 독립된 가상 주소 공간, 파일 디스크립터, 자격 증명, 시그널 상태와 여러 자원 제한을 가진 실행 단위다. 사용자 프로그램은 일반적으로 fork 계열 시스템 호출로 새 프로세스를 만들고 execve를 통해 다른 프로그램 이미지를 적재한다.

커널 내부에서는 하나의 프로세스가 공유하는 상태와 실제 실행 흐름이 구분된다. 프로세스 구조는 주소 공간, 파일 디스크립터와 자격 증명처럼 여러 실행 흐름이 공유하는 정보를 보관하고, 각 스레드 또는 실행 단위는 레지스터 상태, 스케줄링 상태, 시그널 마스크와 커널 스택처럼 개별 실행에 필요한 정보를 가진다.

다중 스레드 프로그램의 스레드들은 같은 프로세스 주소 공간과 열린 파일을 공유하지만 각각 별도의 실행 상태와 스케줄링 대상을 갖는다. 사용자 공간의 POSIX 스레드 라이브러리는 커널의 스레드 기능을 바탕으로 pthread_create, 뮤텍스, 조건 변수와 스레드별 저장소를 제공한다.

프로세스와 스레드는 실행 가능, 수면, 정지와 종료 같은 상태 사이를 이동한다. 실행할 수 없는 스레드는 특정 조건이나 자원을 기다리며 수면 상태에 들어가고, 조건이 충족되면 다시 실행 대기열로 이동한다. 커널 스케줄러는 실행 가능한 스레드를 선택하여 사용 가능한 CPU에서 실행한다.

각 스레드는 사용자 모드와 커널 모드 사이를 오갈 수 있다. 사용자 코드가 시스템 호출을 실행하거나 예외·인터럽트가 발생하면 커널 모드로 전환되며, 요청 처리가 끝나면 저장된 사용자 문맥으로 돌아간다.

시그널은 프로세스와 스레드의 실행을 비동기적으로 알리고 제어하는 수단이다. 일부 시그널 상태는 프로세스 전체가 공유하고, 개별 스레드는 자신만의 시그널 마스크를 가질 수 있다. 커널은 수신된 시그널을 처리할 수 있는 스레드를 선택하고 사용자 공간의 시그널 처리기를 실행하도록 문맥을 구성한다.

프로세스 자격 증명에는 사용자 ID와 그룹 ID, 로그인 정보와 권한 관련 상태가 포함된다. 파일 접근, 프로세스 제어와 보호된 시스템 작업은 현재 프로세스의 자격 증명과 커널 정책을 바탕으로 허용 여부가 결정된다.

프로세스는 pledgeunveil을 호출하여 이후 사용할 수 있는 시스템 기능과 파일 경로를 스스로 제한할 수 있다. 이러한 제한은 프로세스와 실행 흐름에 연결된 커널 상태로 유지되며, 제한이 확정된 뒤에는 일반적으로 다시 넓힐 수 없다.[36][37]

시스템 호출

시스템 호출은 사용자 공간 프로그램이 커널의 보호된 기능을 요청하는 공식 인터페이스다. 파일 열기, 프로세스 생성, 메모리 매핑, 네트워크 통신, 시간 조회와 권한 변경 같은 작업은 시스템 호출을 통해 수행된다.

사용자 프로그램은 일반적으로 C 라이브러리가 제공하는 함수 래퍼를 호출한다. 래퍼는 시스템 호출 번호와 인수를 아키텍처가 정한 방식으로 레지스터나 스택에 배치하고, 특수 명령을 실행하여 사용자 모드에서 커널 모드로 전환한다.

커널의 시스템 호출 진입 코드는 호출 번호를 확인하고 대응하는 처리 함수를 선택한다. 각 인수는 사용자 공간에서 전달되므로 커널이 직접 신뢰하지 않으며, 포인터 범위와 접근 가능 여부를 검사한 뒤 필요한 데이터를 copyin 계열 인터페이스로 커널 공간에 복사한다.

처리 결과는 반환값 또는 오류 번호로 사용자 공간에 전달된다. 시스템 호출이 실패하면 C 라이브러리 래퍼는 보통 -1을 반환하고 커널이 전달한 오류 번호를 errno에 기록한다. 호출별 오류 조건은 각 시스템 호출의 매뉴얼 페이지에 정의된다.

시스템 호출 인터페이스는 커널과 사용자 공간 사이의 보안 경계다. 사용자 프로그램은 커널 주소에 직접 접근할 수 없고, 시스템 호출이 명시적으로 제공하는 작업만 요청할 수 있다. 커널은 자격 증명, 파일 권한, 프로세스 상태와 보안 제한을 확인한 뒤 요청을 수행한다.

pledge는 시스템 호출 번호를 단순히 허용·거부하는 방식보다 프로그램의 기능 범주를 나타내는 promise를 사용한다. 커널은 현재 프로세스에 선언된 promise와 실제 시스템 호출 및 인수를 비교하며, 허용되지 않은 동작이 발생하면 프로세스를 종료할 수 있다.[38]

OpenBSD는 시스템 호출 인터페이스를 영구적인 내부 구현 세부 사항으로 고정하지 않는다. 표준과 사용자 공간 호환성을 고려하되, 위험하거나 사용되지 않는 호출과 호환 계층은 유지 비용과 공격 표면에 따라 제거하거나 수정할 수 있다.

가상 메모리

OpenBSD의 가상 메모리 하위 시스템은 UVM을 기반으로 한다. UVM은 각 프로세스의 가상 주소 공간, 물리 메모리 페이지, 파일 매핑, 익명 메모리, 페이지 폴트와 스왑을 관리하며 커널 내부 메모리 관리에도 사용된다.

각 프로세스는 독립된 가상 주소 공간을 가진다. 동일한 가상 주소가 서로 다른 프로세스에서 사용되더라도 실제로는 서로 다른 물리 페이지에 연결될 수 있다. 이 구조는 프로세스 사이의 메모리를 격리하고, 프로그램이 연속된 주소 공간을 사용하는 것처럼 실행되게 한다.

가상 주소 공간은 코드, 데이터, 힙, 스택, 공유 라이브러리와 mmap으로 생성된 영역으로 구성된다. 각 영역에는 읽기, 쓰기와 실행 권한이 설정되며, 허용되지 않은 방식으로 접근하면 페이지 폴트가 발생하고 프로세스에 시그널이 전달될 수 있다.

아직 물리 메모리가 연결되지 않은 주소를 처음 접근하면 페이지 폴트가 발생한다. UVM은 해당 주소가 유효한 매핑에 포함되는지 확인하고, 필요한 물리 페이지를 할당하거나 파일과 스왑에서 내용을 읽어 페이지 테이블에 연결한다.

프로세스 생성에서는 쓰기 시 복사 방식이 사용될 수 있다. 부모와 자식 프로세스는 처음에는 같은 물리 페이지를 읽기 전용으로 공유하고, 어느 한쪽이 내용을 수정할 때 별도의 페이지를 복사한다. 이를 통해 fork 직후 전체 주소 공간을 즉시 복제하는 비용을 줄인다.

파일 데이터는 VFS와 UVM의 페이지 캐시를 통해 메모리에 유지될 수 있다. 실행 파일과 공유 라이브러리도 파일 기반 메모리 매핑을 사용하며, 같은 파일의 페이지를 여러 프로세스가 공유할 수 있다.

물리 메모리가 부족하면 커널은 사용 빈도가 낮은 페이지를 회수하고, 필요한 경우 익명 메모리를 스왑 장치로 내보낼 수 있다. 커널은 활성·비활성 페이지와 메모리 압력을 추적하면서 사용자 프로세스와 커널 하위 시스템에 필요한 페이지를 공급한다.

OpenBSD는 W^X 정책을 통해 일반적으로 하나의 메모리 영역이 동시에 쓰기 가능하고 실행 가능하지 않도록 제한한다. 실행 파일과 공유 라이브러리는 주소 공간 배치 무작위화의 영향을 받으며, 커널 자체의 메모리 배치도 지원 플랫폼에서 무작위화될 수 있다.

사용자 공간과 커널 공간은 페이지 테이블 권한과 프로세서 보호 기능으로 분리된다. 일부 플랫폼에서는 커널 페이지 테이블 격리와 같은 추가 완화 기술을 적용하여 사용자 모드에서 커널 주소 공간이 노출되는 범위를 줄인다.

파일 시스템

OpenBSD 커널은 VFS라는 가상 파일 시스템 계층을 통해 서로 다른 파일 시스템을 공통 인터페이스로 다룬다. VFS는 커널이 파일 시스템에 요청할 수 있는 작업과 각 파일 시스템 구현이 제공해야 하는 기능을 정의한다.[39]

VFS 구조의 중심에는 vnode가 있다. vnode는 일반 파일, 디렉터리, 장치 파일, 심볼릭 링크와 같은 파일 시스템 객체를 커널 내부에서 공통 방식으로 나타낸다. 각 vnode는 실제 파일 시스템의 inode 또는 이에 대응하는 내부 객체와 연결된다.

사용자 프로그램이 경로 이름을 사용하면 커널의 이름 조회 과정이 디렉터리 vnode를 따라가며 각 경로 구성 요소를 해석한다. 마운트 지점을 만나면 다른 파일 시스템의 루트 vnode로 이동하며, 심볼릭 링크와 현재 디렉터리, 루트 디렉터리도 이 과정에서 처리된다.

파일을 열면 커널은 파일 객체와 파일 디스크립터를 만든다. 파일 디스크립터는 프로세스별 정수 번호이며, 내부 파일 객체는 현재 오프셋, 접근 모드와 해당 vnode 또는 소켓 같은 실제 객체를 참조한다.

VFS는 열기, 읽기, 쓰기, 속성 조회, 디렉터리 검색과 동기화 같은 작업을 vnode 연산으로 전달한다. FFS, NFS와 메모리 기반 파일 시스템 등은 공통 vnode 인터페이스 뒤에서 각자의 저장 형식과 동작을 구현한다.

OpenBSD의 주요 로컬 파일 시스템은 FFS 계통이며, 정식 시스템에서는 FFS2가 일반적으로 사용된다. 소프트 업데이트는 메타데이터 쓰기 순서를 관리하여 파일 시스템 일관성을 유지하면서 동기식 쓰기의 부담을 줄일 수 있다.

장치 파일도 VFS 이름 공간에 나타나지만 일반 파일과 동일한 저장 데이터를 갖는 것은 아니다. 문자 장치와 블록 장치 vnode에 대한 작업은 해당 장치 드라이버의 열기, 읽기, 쓰기와 제어 함수로 전달된다.

파일 시스템 접근은 vnode 권한, 프로세스 자격 증명, 읽기 전용 마운트 여부, 파일 플래그와 unveil 제한 등의 영향을 받는다. 커널은 경로를 찾는 과정과 실제 파일 작업 모두에서 이러한 정책을 검사한다.

장치와 입출력

OpenBSD 커널의 장치 계층은 부팅 중 하드웨어를 탐색하고 적절한 드라이버를 부착하여 장치 트리를 구성한다. 각 장치는 상위 버스나 컨트롤러 아래에 연결되며, 드라이버는 커널의 공통 인터페이스를 통해 장치 기능을 제공한다.

장치 자동 구성은 버스가 발견한 장치의 식별 정보와 자원을 드라이버의 일치 함수에 전달하는 방식으로 이루어진다. 적합한 드라이버가 선택되면 부착 함수가 메모리·입출력 영역, 인터럽트와 DMA 자원을 설정하고 장치를 사용할 수 있는 상태로 만든다.

bus_space 인터페이스는 드라이버가 서로 다른 아키텍처의 장치 레지스터와 버스 메모리에 기계 독립적으로 접근할 수 있게 한다. 같은 장치가 한 플랫폼에서는 입출력 포트, 다른 플랫폼에서는 메모리 매핑 방식으로 연결되더라도 공통 드라이버 코드를 유지할 수 있다.[40]

bus_dma 계층은 장치가 직접 메모리에 데이터를 전송하는 DMA 작업을 추상화한다. 드라이버는 DMA 가능 메모리를 할당하고 주소 매핑과 동기화를 수행하며, 플랫폼별 IOMMU나 캐시 일관성 차이는 기계 의존 구현이 처리한다.

문자 장치는 바이트 흐름 또는 장치별 명령 중심 인터페이스를 제공한다. 터미널, 오디오 장치, 난수 장치와 여러 제어 장치가 여기에 포함된다. 블록 저장 장치는 일반적으로 SCSI 계층과 디스크 드라이버를 거쳐 파일 시스템에 블록 입출력을 제공한다.

저장 장치 요청은 여러 계층을 통과할 수 있다. 파일 시스템은 논리 블록에 대한 읽기나 쓰기를 요청하고, 버퍼·페이지 캐시와 장치 계층은 이를 실제 디스크 명령으로 변환한다. 완료 결과는 인터럽트 또는 비동기 완료 경로를 통해 상위 계층으로 전달된다.

ioctl 시스템 호출은 일반적인 읽기·쓰기만으로 표현하기 어려운 장치 제어 작업에 사용된다. 사용자 공간 프로그램은 파일 디스크립터와 장치별 명령 구조를 전달하고, 커널 드라이버는 권한과 인수를 검사한 뒤 설정을 변경하거나 상태를 반환한다.

OpenBSD는 커널 내부에서 실행되는 바이너리 전용 드라이버를 허용하지 않는다. 일부 장치가 별도의 펌웨어를 필요로 할 수 있지만, 커널 드라이버 자체는 소스 트리 안에서 공개적으로 개발되고 해당 아키텍처의 커널과 함께 빌드된다.

인터럽트와 타이머

인터럽트는 장치나 프로세서가 현재 실행 흐름과 비동기적으로 커널의 처리를 요청하는 방식이다. 네트워크 패킷 수신, 디스크 입출력 완료, 키 입력과 하드웨어 오류 등이 인터럽트를 발생시킬 수 있다.

플랫폼별 인터럽트 컨트롤러는 하드웨어 인터럽트를 특정 CPU와 인터럽트 수준에 전달한다. 커널의 기계 의존 진입 코드는 최소한의 프로세서 상태를 저장하고 등록된 장치 처리 함수를 호출한다.

장치 드라이버는 부착 과정에서 인터럽트 처리기를 등록한다. 처리기는 장치 상태를 확인하고 인터럽트 원인을 승인하며, 완료된 입출력을 상위 계층에 알리거나 추가 작업을 예약한다. 하나의 인터럽트 선을 여러 장치가 공유하는 구조에서는 각 처리기가 자신의 장치가 원인인지 확인한다.

하드웨어 인터럽트 문맥에서는 수면하거나 오래 걸리는 작업을 수행할 수 없으므로 처리량을 최소화해야 한다. 즉시 끝낼 필요가 없는 작업은 소프트 인터럽트, 작업 큐 또는 커널 스레드로 넘겨 더 낮은 우선순위의 문맥에서 처리할 수 있다.

OpenBSD의 전통적인 spl 계층은 특정 종류의 인터럽트를 일시적으로 차단하거나 현재 인터럽트 우선순위를 높이는 인터페이스를 제공한다. 이는 같은 자료구조에 접근하는 인터럽트 처리와 일반 커널 코드 사이의 경쟁을 제어하는 데 사용되어 왔다.[41]

다중 프로세서 환경에서는 단순히 로컬 CPU의 인터럽트만 막는 것으로 다른 CPU의 접근까지 막을 수 없으므로 뮤텍스와 원자적 연산 같은 별도의 동기화가 필요하다. 현대 OpenBSD 커널에서는 인터럽트 안전 잠금과 CPU별 자료구조를 사용하여 병렬 실행을 제어한다.

하드클록은 일정 주기로 발생하여 시스템 시간, 프로세스 실행 시간, 스케줄링과 여러 커널 통계를 갱신한다. 플랫폼에 따라 별도의 통계 클록과 고해상도 시간 계측기가 사용될 수 있다.

지연 실행 작업에는 timeout 인터페이스가 사용된다. 커널 코드는 timeout 객체에 콜백을 등록하고 일정 시간이 지난 뒤 실행하도록 예약하거나, 기존 예약을 취소·갱신할 수 있다.[42]

정확한 시간 측정에는 하드웨어 타임카운터가 사용된다. 커널은 여러 후보 장치 가운데 품질이 적합한 시간 소스를 선택하며, 단조 시간과 실제 시각을 계산하여 사용자 공간의 시간 관련 시스템 호출에 제공한다.

멀티프로세서 지원

OpenBSD는 여러 CPU 코어를 사용할 수 있는 대칭형 다중 처리 구조를 지원한다. 지원 플랫폼의 다중 프로세서 커널에서는 각 CPU가 사용자 프로세스와 커널 코드를 실행할 수 있으며, 스케줄러가 실행 가능한 스레드를 CPU 사이에 배치한다.

초기 OpenBSD SMP 구현은 커널 대부분을 하나의 큰 잠금, 이른바 Big Kernel Lock로 보호하였다. 한 CPU가 잠금을 잡고 커널 코드를 실행하는 동안 다른 CPU는 같은 영역을 동시에 실행할 수 없었으므로 구현은 단순했지만 코어 수가 늘어날수록 병렬성이 제한되었다.

이후 네트워크 스택, 파일 시스템, 장치 드라이버와 여러 공통 하위 시스템이 세분화된 잠금과 CPU별 자료구조를 사용하도록 점진적으로 전환되었다. 특정 경로가 MP-safe로 표시되면 큰 커널 잠금 없이 여러 CPU에서 병렬로 실행될 수 있다.

커널은 뮤텍스, 읽기·쓰기 잠금, 참조 횟수, 원자 연산과 메모리 장벽을 사용하여 공유 자료구조를 보호한다. 인터럽트 문맥과 프로세스 문맥이 함께 접근하는 자료구조에는 인터럽트 안전 잠금이 필요할 수 있다.

각 CPU는 현재 실행 중인 스레드, 실행 대기열과 여러 통계·캐시 상태를 별도로 가질 수 있다. 자주 접근하는 자료를 CPU별로 나누면 전역 잠금 경쟁과 캐시 라인 이동을 줄일 수 있다.

프로세스나 스레드는 실행 중 다른 CPU로 이동할 수 있으며, 일부 커널 작업과 인터럽트는 특정 CPU에 결합될 수 있다. CPU 간 인터럽트는 다른 CPU에 재스케줄링, TLB 갱신이나 정지 같은 작업을 요청하는 데 사용된다.

멀티프로세서 지원은 단순한 성능 기능에 그치지 않는다. 여러 CPU에서 같은 코드가 동시에 실행되면 단일 CPU 환경에서는 나타나지 않던 경쟁 조건, 참조 수명 오류와 메모리 순서 문제가 드러나므로, 잠금 규칙과 객체 수명을 명확하게 설계해야 한다.

OpenBSD는 모든 커널 경로를 한 번에 병렬화하기보다 하위 시스템별로 큰 잠금의 범위를 줄이는 방식을 사용해 왔다. 남아 있는 직렬화 구간은 정확성과 유지보수성을 고려하면서 점진적으로 세분화된다.

커널 보안 구조

OpenBSD의 커널 보안은 하나의 접근 제어 기능이 아니라 사용자·커널 격리, 프로세스 권한, 메모리 보호, 시스템 호출 제한, 파일 시스템 정책, 난수 생성과 커널 자체 보호를 결합한 다층 구조다.

가장 기본적인 경계는 사용자 모드와 커널 모드의 분리다. 사용자 프로그램은 커널 메모리와 장치 레지스터에 직접 접근할 수 없고, 검증된 시스템 호출 인터페이스를 통해서만 보호된 작업을 요청한다.

커널은 각 프로세스의 실제·유효 사용자 ID, 그룹, 파일 권한과 여러 자격 증명을 확인한다. 전통적으로 root가 광범위한 권한을 갖지만, 많은 시스템 데몬은 시작 뒤 전용 사용자로 권한을 낮추거나 필요한 작업만 수행하는 별도 프로세스로 분리된다.

보안 수준인 securelevel은 시스템이 다중 사용자 상태로 들어간 뒤 일부 강한 권한을 root에게서도 제한한다. 설정된 수준에 따라 커널 메모리와 장치에 대한 쓰기, 파일 플래그 해제, 마운트 상태 변경과 시간 역행 같은 작업이 제한될 수 있다.[43]

pledge는 프로세스가 사용할 수 있는 시스템 기능 범주를 제한한다. 커널은 시스템 호출과 인수를 검사하여 선언된 promise 밖의 작업을 차단하며, 기본 시스템의 많은 프로그램이 초기화 후 필요 없는 기능을 포기하는 데 사용한다.[44]

unveil은 프로세스에 보이는 파일 시스템 경로와 허용 작업을 제한한다. 경로별로 읽기, 쓰기, 실행과 생성 권한을 부여할 수 있으며, 설정을 잠근 뒤에는 프로세스가 새로운 경로를 추가할 수 없다.[45]

메모리 보호에는 W^X, 주소 공간 배치 무작위화, 위치 독립 실행 파일, 스택 보호와 가드 페이지가 포함된다. 이러한 기술은 메모리 손상 오류를 제거하지는 않지만 공격자가 데이터를 실행 코드로 사용하거나 코드와 커널 객체의 위치를 예측하기 어렵게 만든다.

커널과 사용자 프로그램에 필요한 난수는 커널 난수 하위 시스템이 제공한다. 여러 하드웨어와 시스템 이벤트에서 수집한 엔트로피를 혼합하며, /dev/random, getentropyarc4random 계열 인터페이스의 기반이 된다.[46]

커널은 사용자 공간 포인터를 직접 역참조하지 않고 전용 복사 인터페이스를 사용한다. 시스템 호출과 장치 제어 명령은 길이, 플래그, 객체 상태와 권한을 확인해야 하며, 사용자 입력을 커널 내부 자료구조로 사용하기 전에 검증한다.

장치 메모리와 DMA는 시스템 전체 메모리에 영향을 줄 수 있으므로 드라이버 계층에서 통제된다. 지원되는 플랫폼에서는 IOMMU가 장치의 DMA 접근 범위를 제한할 수 있으며, bus_dma 인터페이스가 장치에 노출할 메모리 매핑을 관리한다.

읽기 전용 커널 영역, 실행 권한 분리와 커널 주소 무작위화는 커널 자체를 보호한다. 커널 텍스트와 민감한 자료구조를 임의로 수정할 수 있는 인터페이스는 제한되며, 바이너리 커널 모듈을 통한 실행 중 코드 삽입도 일반적인 기능으로 제공하지 않는다.

OpenBSD의 커널 보안 구조는 하나의 방어가 모든 공격을 차단한다고 가정하지 않는다. 시스템 호출 제한, 파일 접근 제한, 메모리 보호, 권한 분리와 난수화를 겹쳐 적용하여 하나의 구성 요소가 침해되더라도 공격자가 사용할 수 있는 기능과 접근 범위를 단계적으로 줄이는 방향을 따른다.

보안 구조

OpenBSD의 보안 구조는 하나의 방화벽, 접근 제어 기능이나 취약점 대응 체계로 이루어지지 않는다. 설치 직후의 기본 구성, 소스 코드 감사, 최소 권한, 프로세스 격리, 시스템 호출과 파일 접근 제한, 메모리 보호, 암호화, 난수 생성과 업데이트 체계를 여러 계층으로 겹쳐 적용한다.

이러한 구조는 프로그램에 결함이 존재할 수 있다는 전제에서 출발한다. 코드 감사는 결함의 수를 줄이고, 안전한 기본 구성은 외부에 노출되는 기능을 줄이며, 권한 분리와 pledge, unveil은 침해된 프로그램이 사용할 수 있는 자원을 제한한다. W^X, 주소 공간 무작위화와 실행 흐름 보호는 남아 있는 메모리 오류를 실제 코드 실행으로 연결하기 어렵게 만든다.

OpenBSD는 이를 선제적 보안으로 설명한다. 이미 알려진 취약점만 패치하는 것이 아니라, 아직 공격에 사용되지 않은 오류 유형과 위험한 설계 패턴을 소스 트리 전체에서 찾아 제거하고 새로운 완화 기술을 기본 시스템 전반에 적용한다.[47]

보안 기능은 대개 선택적으로 설치하는 별도 제품이 아니라 커널, C 라이브러리, 런타임 링커, 컴파일러 설정과 기본 데몬에 통합된다. 이에 따라 일반적인 기본 프로그램도 여러 완화 기술의 적용을 받으며, 기능을 활용하기 위해 사용자가 각 프로그램을 별도로 다시 컴파일할 필요가 없다.

기본적으로 안전한 구성

OpenBSD는 보안을 설치 뒤 관리자가 추가하는 강화 작업으로만 보지 않고, 초기 상태부터 불필요한 노출을 줄이는 방향으로 기본 구성을 정한다. 사용자가 기능을 명시적으로 활성화하는 구조가, 필요하지 않은 서비스를 설치 뒤 찾아서 끄는 구조보다 안전하다는 관점이다.

기본 설치에서는 네트워크를 통해 접근할 수 있는 서비스가 제한적으로 구성된다. 프로그램이 설치되어 있다는 사실과 해당 서비스가 실제로 외부 연결을 기다리며 실행되고 있다는 사실은 구분된다. 서버 기능은 관리자가 목적에 맞게 활성화하고 설정한 뒤 사용한다.

서비스 활성화와 시작 옵션은 rcctl/etc/rc.conf.local을 통해 관리한다. 기본 시스템의 부팅 스크립트를 직접 수정하는 대신 로컬에서 활성화한 서비스와 옵션만 별도로 기록하므로, 현재 시스템에서 어떤 기능이 켜져 있는지 비교적 명확하게 확인할 수 있다.

기본 데몬은 가능한 경우 전용 사용자와 제한된 디렉터리, 낮은 권한으로 실행된다. 높은 권한이 필요한 작업이 있더라도 전체 프로그램이 계속 root로 동작하기보다 초기화 단계에서만 자원을 확보한 뒤 권한을 낮추거나, 작은 권한 프로세스로 해당 작업을 분리한다.

파일과 디렉터리의 기본 권한, 시스템 계정, 설정 파일 위치와 서비스 실행 환경도 기본 보안 모델의 일부다. 관리자가 명시적으로 허용하지 않은 사용자가 비밀 키, 암호 데이터베이스와 시스템 설정을 읽거나 수정하지 못하도록 접근 권한을 구분한다.

OpenBSD는 새 기능을 추가할 때 기본 활성화 여부도 보안 관점에서 결정한다. 널리 사용되는 기능이라도 외부 입력과 권한을 크게 늘리거나 안전한 기본 동작을 정하기 어렵다면 자동으로 활성화하지 않을 수 있다.

안전한 기본값은 모든 환경에 동일한 설정이 적합하다는 뜻은 아니다. 관리자는 시스템 목적에 맞게 네트워크 서비스와 접근 기능을 추가할 수 있지만, 그 과정에서 새롭게 열리는 인터페이스와 권한을 명시적으로 선택하게 된다.

소스 코드 감사

소스 코드 감사는 OpenBSD 보안 개발의 핵심 과정이다. 개발자들은 특정 취약점이 보고된 파일만 수정하는 데 그치지 않고, 같은 오류 유형이 다른 프로그램과 라이브러리에도 존재할 가능성을 조사한다.

감사 대상에는 버퍼 범위 오류, 정수 오버플로와 잘림, 초기화되지 않은 메모리, 해제 후 사용, 잘못된 오류 처리, 경쟁 조건, 임시 파일 생성, 파일 권한, 예측 가능한 난수와 불필요하게 유지되는 권한이 포함된다.

한 종류의 결함이 발견되면 소스 트리 전체에서 유사한 코드 패턴을 검색한다. 이미 검토했던 코드도 새로운 오류 유형과 공격 기법이 알려지면 다시 감사한다. 따라서 코드 감사는 한 번 끝나는 인증 절차가 아니라 계속 반복되는 개발 활동이다.

OpenBSD는 보안 버그와 일반적인 코드 품질 문제를 완전히 분리하지 않는다. 잘못된 경계 검사, 모호한 객체 수명이나 오류 반환값의 무시는 당장 공격 경로가 확인되지 않더라도 이후 보안 문제로 발전할 수 있다. 이에 따라 정확성 향상 자체를 보안 작업으로 취급한다.

감사 과정에서는 개별 오류를 고치는 것 외에 잘못 사용하기 쉬운 인터페이스를 대체하기도 한다. strlcpy, strlcat, arc4random_uniform, reallocarray, recallocarrayexplicit_bzero 같은 인터페이스는 크기 계산, 난수 범위와 민감한 메모리 제거에서 반복되던 오류를 줄이기 위해 도입되거나 확산되었다.

코드의 양과 복잡성도 감사 가능성에 영향을 준다. 거의 사용되지 않는 기능, 중복된 구현, 오래된 호환 계층과 복잡한 조건부 코드는 검토해야 할 상태를 늘린다. OpenBSD는 필요한 경우 이러한 코드를 제거하거나 더 작은 구현으로 대체한다.

OpenBSD의 공식 보안 문서는 공개 개발 모델을 통해 상용 공급자가 호환성이나 제품 일정 때문에 선택하기 어려운 변경도 적용할 수 있다고 설명한다. 위험한 인터페이스를 교체하거나 오래된 기능을 제거하는 작업이 이에 해당한다.[48]

최소 권한 원칙

최소 권한 원칙은 프로그램과 사용자가 자신의 작업에 필요한 권한만 가지도록 하는 설계 원칙이다. OpenBSD는 사용자 계정, 파일 권한, 프로세스 자격 증명, 시스템 호출과 파일 시스템 접근 범위에 이를 적용한다.

네트워크 데몬과 시스템 서비스는 가능한 경우 각각 전용 계정으로 실행된다. 해당 계정은 일반 사용자 파일이나 다른 서비스의 데이터에 접근할 필요가 없으며, 로그인 셸과 홈 디렉터리 사용도 제한될 수 있다.

프로그램이 시작할 때 root 권한이 필요하더라도 이후 모든 작업에서 이를 유지할 필요는 없다. 보호된 포트를 열거나 장치와 파일을 준비한 뒤 사용자 ID와 그룹 ID를 낮춰 일반 권한으로 실행할 수 있다.

파일 디스크립터도 권한의 일부로 볼 수 있다. 높은 권한이 필요한 프로세스가 필요한 파일이나 소켓을 먼저 열고, 제한된 프로세스에 해당 디스크립터만 전달하면 제한된 프로세스는 전체 파일 시스템을 탐색하지 않고 필요한 자원만 사용할 수 있다.

chroot는 프로세스가 볼 수 있는 파일 시스템의 루트를 특정 디렉터리로 제한하는 데 사용된다. 이것만으로 완전한 격리를 제공하지는 않지만 전용 사용자, 권한 폐기, pledgeunveil 같은 다른 제한과 함께 피해 범위를 줄이는 계층으로 사용된다.

시스템 관리 권한도 전부 또는 전무로만 제공하지 않는다. doas를 이용하면 특정 사용자가 특정 명령을 다른 사용자 권한으로 실행하도록 제한할 수 있다. 이를 통해 모든 관리 작업에서 root 셸을 유지하는 방식을 줄일 수 있다.

최소 권한은 기능을 수행하지 못할 정도로 모든 접근을 제거하는 정책이 아니다. 필요한 자원과 작업을 먼저 정의하고, 해당 범위 밖의 권한을 제거하여 오류나 침해가 다른 부분으로 확산되는 것을 줄이는 구조다.

권한 분리와 권한 폐기

권한 분리는 하나의 프로그램을 서로 다른 역할과 권한을 가진 여러 프로세스로 나누는 구조다. 외부에서 입력을 받는 복잡한 코드와 실제 시스템 변경을 수행하는 높은 권한 코드를 분리하여, 공격 가능성이 높은 부분이 직접 root 권한을 갖지 않게 한다.

대표적인 구조에서는 작은 감시 프로세스만 높은 권한을 유지하고, 네트워크 프로토콜 해석과 사용자 요청 처리는 비권한 프로세스가 담당한다. 두 프로세스는 제한된 메시지 인터페이스로 통신하며, 권한 프로세스는 요청의 종류와 인수를 다시 검증한다.

OpenSSH는 이러한 권한 분리 구조를 널리 알린 구성 요소다. 네트워크에 노출되는 sshd 프로세스가 침해되더라도 인증과 세션 생성에 필요한 높은 권한 작업을 별도 프로세스가 제한적으로 수행하도록 발전하였다.

OpenBGPD, OpenSMTPD, dhclient, X 서버와 여러 기본 데몬에도 역할별 프로세스 분리가 적용되어 왔다. OpenBSD는 새 데몬을 설계하거나 기존 프로그램을 개편할 때 입력 파서, 네트워크 처리, 파일 접근과 권한 작업을 분리할 수 있는지 검토한다.

권한 폐기는 프로그램이 한때 필요했지만 이후에는 필요하지 않은 권한을 영구적으로 버리는 방식이다. 사용자와 그룹 ID를 낮추고, 보조 그룹을 제거하며, 루트 디렉터리를 바꾸고, 열려 있는 파일 디스크립터를 정리하는 작업이 포함된다.

권한 폐기는 초기화 순서와 연결된다. 프로그램은 필요한 소켓과 파일을 열고 설정을 읽은 뒤 권한을 낮춘다. 이후 공격자가 실행 흐름을 장악하더라도 이미 폐기된 root 권한이나 닫힌 자원에 다시 접근하기 어렵다.

OpenBSD 3.3 릴리스 당시에도 set-user-ID와 set-group-ID 프로그램 수를 줄이고, 남아 있는 프로그램이 필요한 자원을 확보한 뒤 빠르게 권한을 폐기하도록 하는 작업이 진행되었다.[49]

권한 분리는 프로그램 구조를 복잡하게 만들 수 있으므로 프로세스 사이의 통신 규약이 명확해야 한다. OpenBSD는 imsg 계열 인터페이스처럼 크기와 형식이 정해진 메시지를 사용하여, 제한된 프로세스가 권한 프로세스에 임의의 작업을 요청하지 못하게 한다.

pledge

pledge는 프로세스가 앞으로 사용할 운영체제 기능의 범주를 선언하고, 그 범위를 벗어난 작업을 커널이 차단하는 시스템 호출이다. 프로그램의 의도된 동작을 커널이 강제하는 응용 프로그램별 시스템 호출 제한 기능으로 볼 수 있다.

프로그램은 stdio, rpath, wpath, inet, dns, proc, exec처럼 기능 범주를 나타내는 promise 문자열을 지정한다. 커널은 이후 실행되는 시스템 호출과 인수를 해당 promise에 대조한다.

pledge는 시스템 호출 번호만 단순히 필터링하지 않는다. 같은 시스템 호출이라도 인수와 수행하려는 작업에 따라 필요한 promise가 달라질 수 있다. 파일 열기, 소켓 생성과 프로세스 제어 같은 동작을 의미 단위로 제한한다.

프로그램은 초기화 단계에서 넓은 promise 집합을 사용한 뒤 설정과 자원을 준비하고 더 좁은 범위로 다시 pledge할 수 있다. 한 번 제거한 promise는 일반적으로 다시 추가할 수 없으므로 실행이 진행될수록 권한을 줄이는 구조를 만들 수 있다.

허용되지 않은 동작을 시도하면 기본적으로 프로세스에 치명적인 시그널이 전달되고 실행이 중단된다. 이는 프로그램의 정상 경로에 존재하지 않아야 할 동작이 발생했음을 나타내며, 침해 이후 사용할 수 있는 커널 기능을 제한한다.

pledge는 일반적인 샌드박스 정책 파일을 관리자가 외부에서 작성하는 방식보다 프로그램 개발자가 코드의 각 단계에서 필요한 기능을 직접 선언하는 방식을 지향한다. 프로그램 구조와 정책을 같은 소스 코드에서 유지할 수 있다는 특징이 있다.

OpenBSD 기본 시스템의 많은 명령어와 데몬이 pledge를 사용한다. 단순한 파일 처리 도구부터 네트워크 서비스까지 각 실행 단계에 필요한 promise만 유지하도록 수정되어 왔다.

pledge는 메모리 손상이나 논리 오류를 제거하지 않는다. 대신 프로그램이 장악되었을 때 공격자가 새 프로세스를 실행하거나 임의의 네트워크 연결을 만들고, 관련 없는 파일을 읽는 등의 후속 행동을 제한한다.[50]

unveil

unveil은 프로세스가 볼 수 있는 파일 시스템 경로와 각 경로에서 허용되는 작업을 제한하는 시스템 호출이다. pledge가 운영체제 기능의 종류를 제한한다면, unveil은 파일 시스템의 이름 공간을 프로그램별로 축소한다.

프로그램은 경로와 함께 읽기, 쓰기, 실행과 생성 권한을 나타내는 문자열을 등록한다. 예를 들어 설정 파일에는 읽기만 허용하고, 작업 디렉터리에는 읽기와 쓰기를 허용하며, 실행해야 할 프로그램에는 실행 권한을 지정할 수 있다.

필요한 경로를 모두 등록한 뒤 unveil(NULL, NULL)을 호출하면 설정을 잠글 수 있다. 잠긴 뒤에는 새로운 경로를 추가하거나 기존 권한을 넓힐 수 없다.

허용되지 않은 경로는 단순히 권한 부족으로만 보이는 것이 아니라 프로세스의 파일 시스템 관점에서 존재하지 않는 것처럼 처리될 수 있다. 이에 따라 침해된 프로그램이 시스템 전체의 디렉터리 구조와 민감한 파일을 탐색하는 것을 줄인다.

unveilchroot보다 세밀한 경로별 권한을 제공하며 root 권한 없이도 적용할 수 있다. 하나의 디렉터리 트리 전체를 새 루트로 만드는 대신 여러 위치에서 필요한 파일과 디렉터리만 선택적으로 공개할 수 있다.

pledge와 함께 사용하면 프로그램이 파일 관련 시스템 호출을 수행할 수 있더라도 unveil로 공개된 경로에만 접근하게 만들 수 있다. 반대로 파일 경로가 공개되어 있더라도 필요한 promise가 없으면 해당 종류의 작업을 수행할 수 없다.

동적 링커와 로케일, 인증서, 이름 해석 설정처럼 프로그램 실행에 필요한 공통 파일도 고려해야 한다. 일반적으로 프로그램은 초기화 과정에서 필요한 자원을 먼저 열거나, 실제 접근해야 하는 경로를 등록한 뒤 제한을 잠근다.

unveil은 OpenBSD 6.4에서 도입되었으며 기본 시스템의 프로그램에 빠르게 적용되었다. 이후 포트와 외부 소프트웨어에서도 OpenBSD 전용 보안 계층으로 사용할 수 있게 되었다.[51]

W^X

W^X는 메모리 페이지가 동시에 쓰기 가능하고 실행 가능하지 않도록 하는 정책이다. 이름은 writable XOR executable에서 유래하며, 하나의 메모리 영역은 쓰기와 실행 가운데 하나의 성질만 가져야 한다는 원칙을 나타낸다.

일반 프로그램은 실행 코드가 들어 있는 페이지를 읽기·실행 가능하게 두고, 데이터와 스택은 읽기·쓰기 가능하지만 실행할 수 없게 둔다. 공격자가 버퍼 오버플로로 데이터 영역에 기계어 코드를 기록하더라도 해당 영역을 직접 실행하기 어렵게 한다.

OpenBSD는 3.3에서 여러 아키텍처에 W^X를 적용하기 시작했고, 이후 지원 범위를 확장하였다. OpenBSD 6.0부터는 사용자 공간 W^X를 기본적으로 엄격하게 적용하며, 예외가 필요한 실행 파일은 별도 표식과 wxallowed 마운트 옵션을 필요로 한다.[52]

동적 링커는 프로그램 적재와 심볼 재배치 과정에서 일부 메모리를 수정해야 한다. OpenBSD는 재배치가 끝난 영역을 읽기 전용으로 전환하고, 다중 스레드 프로그램에서도 지연 바인딩이 W^X를 위반하지 않도록 kbind 같은 커널 지원 기능을 도입하였다.

JIT 컴파일러처럼 실행 중 코드를 생성하는 프로그램은 W^X 아래에서 메모리 권한 전환을 명확하게 처리해야 한다. 쓰기와 실행 권한을 동시에 유지하는 대신 코드를 생성하는 단계와 실행하는 단계를 분리한다.

W^X만으로 코드 재사용 공격을 막을 수는 없다. 이미 존재하는 실행 코드 조각을 연결하는 공격도 가능하므로 주소 공간 무작위화, 제어 흐름 보호와 시스템 호출 진입 제한 같은 기능이 함께 사용된다.

주소 공간 배치 무작위화

주소 공간 배치 무작위화는 실행할 때마다 프로그램 코드, 공유 라이브러리, 스택, 힙과 메모리 매핑의 위치를 바꾸는 기술이다. 공격자가 특정 함수, 데이터나 코드 조각의 주소를 미리 예측하기 어렵게 한다.

OpenBSD는 3.4에서 주소 공간 배치 무작위화를 기본 제공했으며, 이후 무작위화되는 영역과 엔트로피를 확대하였다. 프로젝트는 이를 기본 활성화한 초기 범용 운영체제 가운데 하나로 설명한다.[53]

실행 파일 자체를 무작위 위치에 적재하려면 위치 독립 실행 파일이 필요하다. OpenBSD는 PIE를 시스템 전반에 적용하고, 정적으로 연결된 /bin, /sbin과 설치 램디스크 프로그램에도 static PIE를 도입하였다.

공유 라이브러리의 기본 주소뿐 아니라 라이브러리 내부 객체 순서도 무작위화할 수 있다. 부팅 과정에서 libc, libcrypto와 런타임 링커를 다시 연결하여 내부 함수와 데이터의 상대적 배치까지 달라지게 하는 방식이 사용된다.

커널도 지원 플랫폼에서 주소와 객체 배치를 무작위화한다. 사용자 공간 공격자가 커널 코드나 자료구조의 위치를 예측해야 하는 공격에서 추가적인 장애물로 작용한다.

무작위화는 주소 정보가 노출되면 효과가 줄어들 수 있다. 따라서 포인터 노출 방지, 메모리 읽기 제한, 프로세스 격리와 함께 사용하며, 하나의 주소 유출이 전체 배치를 드러내지 않도록 여러 영역을 독립적으로 무작위화하는 방향으로 발전해 왔다.

실행 파일과 라이브러리 보호

OpenBSD는 실행 파일과 공유 라이브러리를 위치 독립적으로 빌드하고, 적재가 끝난 뒤 변경할 필요가 없는 메모리 영역을 읽기 전용으로 전환한다. 실행 코드와 주요 메타데이터가 프로그램 실행 중 임의로 수정되는 것을 줄이기 위한 구조다.

PIE는 실행 파일을 고정 주소에 연결하지 않고 임의의 주소에 적재할 수 있게 한다. OpenBSD는 5.3에서 여러 플랫폼의 기본 시스템에 PIE를 전역 적용했으며 이후 지원 범위를 넓혔다.[54]

RELRO는 동적 링커가 재배치를 완료한 뒤 GOT와 다른 재배치 관련 영역을 읽기 전용으로 바꾼다. 공격자가 함수 호출 경로를 변경하기 위해 심볼 주소 테이블을 덮어쓰는 방식을 어렵게 한다.

OpenBSD의 런타임 링커는 자신이 수정해야 하는 영역을 제한하고, 일반 프로그램이 GOT와 PLT를 변경하지 못하게 한다. 생성자와 소멸자 목록 등 프로그램 흐름에 영향을 미칠 수 있는 자료도 적재가 끝난 뒤 보호한다.

공유 라이브러리마다 별도의 스택 보호 쿠키를 가질 수 있으며, 임의 데이터가 필요한 ELF 영역은 프로그램 적재 시 커널 또는 링커가 난수로 초기화한다. 하나의 쿠키가 노출되더라도 모든 라이브러리에 동일한 값을 적용하지 않도록 한다.

RETGUARD는 지원되는 코드에서 함수 반환 주소를 보호하기 위한 OpenBSD의 제어 흐름 완화 기술이다. 함수별 비밀값을 이용하여 반환 주소의 무결성을 확인하고, 스택 손상으로 반환 흐름이 변조되는 공격을 어렵게 한다.

실행 파일 형식에는 OpenBSD 전용 표식과 메타데이터가 포함될 수 있다. 커널과 런타임 링커는 이를 이용하여 W^X 예외, 시스템 호출 진입 위치와 보안 속성을 검증한다.

스택과 메모리 보호

스택 보호는 함수의 지역 버퍼와 제어 정보 사이에 무작위 값인 스택 쿠키를 두고, 함수가 반환하기 전에 값이 변경되었는지 검사하는 기술이다. 스택 기반 버퍼 오버플로가 반환 주소를 덮어썼을 때 실행을 중단하게 한다.

OpenBSD는 ProPolice 계통의 스택 보호 기능을 통합하고 OpenBSD 3.3부터 기본 시스템 전체에 기본 적용하였다. 이후 여러 하드웨어 아키텍처와 공유 라이브러리 단위의 별도 쿠키로 확장하였다.[55]

스택 주변에는 접근할 수 없는 가드 페이지를 둘 수 있다. 스택이 지정된 범위를 크게 벗어나면 다른 메모리 객체를 덮어쓰기보다 페이지 폴트가 발생한다. 각 스레드의 스택에도 이러한 경계를 적용할 수 있다.

메모리 영역은 필요한 권한만 갖도록 나뉜다. 코드에는 쓰기 권한이 없고, 일반 데이터에는 실행 권한이 없으며, 재배치 후 변경할 필요가 없는 데이터는 읽기 전용으로 전환된다.

민감한 데이터의 삭제에는 컴파일러 최적화로 제거되지 않는 explicit_bzero 같은 함수를 사용한다. 암호 키와 비밀번호가 사용 뒤에도 프로세스 메모리에 불필요하게 남는 것을 줄인다.

크기 계산이 포함된 메모리 할당에는 reallocarrayrecallocarray 같은 인터페이스를 사용할 수 있다. 요소 개수와 크기의 곱이 정수 범위를 넘으면 실패하여, 작은 버퍼를 할당한 뒤 큰 데이터를 기록하는 오류를 방지한다.

읽기·쓰기 범위를 벗어난 접근과 해제 후 사용을 완전히 막을 수는 없지만, 가드 페이지, 무작위 배치, 할당 크기 검증과 할당기 검사를 결합하여 오류가 조용한 데이터 손상보다 즉각적인 실패로 나타나도록 한다.

malloc 보호 기능

OpenBSD의 malloc 구현은 성능과 메모리 절약뿐 아니라 힙 손상과 해제 후 사용을 탐지하거나 악용하기 어렵게 하는 데 초점을 둔다. 일반 프로그램은 별도 보안 할당기를 설치하지 않아도 기본 C 라이브러리의 강화된 할당기를 사용한다.

할당되는 메모리의 위치와 내부 메타데이터 배치는 무작위화된다. 동일한 실행 흐름에서도 객체 주소와 인접 관계가 일정하지 않게 하여 공격자가 특정 힙 배치를 반복적으로 만들기 어렵게 한다.

큰 할당 주변에는 접근할 수 없는 가드 페이지를 둘 수 있다. 경계를 넘는 읽기나 쓰기가 인접 객체를 손상하기보다 즉시 접근 오류를 발생시키도록 한다.

해제된 메모리를 즉시 같은 용도의 할당에 반환하지 않고 일정 시간 지연하거나 무작위 순서로 재사용할 수 있다. 해제된 객체의 주소를 계속 사용하는 버그가 새로운 민감 객체를 조작하는 공격으로 이어지는 가능성을 줄인다.

작은 할당의 끝부분에 사용되지 않는 공간이 있으면 이를 검사하여 경계 밖 쓰기의 흔적을 찾을 수 있다. 내부 자료구조와 할당 상태가 예상과 다르면 프로그램을 중단하여 손상을 조기에 드러낸다.

malloc.confMALLOC_OPTIONS를 통해 일부 검사와 동작을 조정할 수 있지만, 기본 설정 자체가 여러 보호 기능을 사용한다. set-user-ID와 같은 특권 프로그램에서는 환경 변수로 보안 동작을 약화하지 못하도록 처리한다.

freezero는 메모리를 해제하기 전에 지정된 영역을 명시적으로 지우며, recallocarray는 배열 크기를 변경할 때 축소되는 부분을 지우고 새 영역을 초기화하는 데 사용할 수 있다.

강화된 할당기는 메모리 오류를 자동 수정하지 않는다. 오류를 더 빠르게 발견하고 힙 배치를 예측하기 어렵게 하며, 하나의 오류가 안정적인 공격 기법으로 발전하는 비용을 높이는 역할을 한다.[56]

시그널과 시스템 호출 보호

시그널 처리는 사용자 공간의 제어 흐름을 비동기적으로 변경하므로 공격 대상이 될 수 있다. 커널은 시그널을 전달할 때 사용자 스택에 복귀 문맥을 만들고, 처리기가 끝난 뒤 검증된 경로를 통해 원래 실행 상태로 돌아가게 한다.

과거에는 공격자가 위조한 시그널 프레임을 만들어 sigreturn을 호출하고 레지스터 상태를 원하는 값으로 바꾸는 SROP 기법을 사용할 수 있었다. OpenBSD는 커널이 직접 생성하고 추적한 시그널 문맥만 복원할 수 있도록 제한하여 이러한 공격을 완화하였다.

시그널 처리기 안에서 안전하지 않은 함수를 호출하면 전역 상태와 메모리 할당기가 손상될 수 있다. OpenBSD의 시스템 프로그램은 시그널 처리기에서 최소한의 플래그만 설정하고 실제 처리를 정상 실행 흐름으로 넘기는 방식을 사용한다.

시스템 호출은 사용자 공간에서 커널 기능으로 들어가는 경로다. OpenBSD는 pledge로 호출 가능한 기능 범주를 제한하는 것 외에, 시스템 호출 명령이 실행될 수 있는 사용자 공간 위치도 제한한다.

pinsyscalls는 각 시스템 호출 번호에 대응하는 시스템 호출 진입 명령의 정확한 위치를 커널에 등록한다. 다른 주소에서 해당 시스템 호출을 실행하려 하면 SIGABRT가 발생한다. 동적 프로그램에서는 ld.solibc 안의 호출 위치를 커널에 전달한다.[57]

이 구조는 공격자가 임의의 실행 가능 메모리에서 직접 시스템 호출 명령을 찾아 사용하는 방식을 제한한다. 공격자는 허용된 라이브러리의 정확한 진입 위치와 해당 시스템 호출 번호를 함께 알아야 한다.

kbind는 런타임 링커가 다중 스레드 프로그램의 지연 바인딩을 수행할 때 임의의 사용자 코드가 재배치 정보를 위조하지 못하도록 커널이 제한된 메모리 수정을 대신 수행하는 인터페이스다.

이러한 기능은 정상적인 프로그램이 C 라이브러리와 런타임 링커를 통해 시스템 호출을 사용하는 경로를 강화한다. 사용자 공간에서 임의의 기계어를 실행할 수 있게 된 뒤에도 커널 진입 경로를 추가로 제한하는 방어 계층이다.

보안 난수 생성

OpenBSD는 암호 키, 세션 식별자, 주소 공간 배치와 여러 완화 기술에 사용할 난수를 커널 난수 하위 시스템에서 제공한다. 난수 생성은 보안 기능의 기반이므로 일반적인 의사 난수 함수와 구분된다.

커널은 하드웨어 난수 장치, 인터럽트 시점, 장치 이벤트와 부팅 과정에서 얻은 여러 입력을 내부 상태에 혼합한다. 단일 하드웨어 난수 명령의 결과를 그대로 신뢰하기보다 여러 출처를 결합한다.

사용자 공간 프로그램은 getentropy를 통해 제한된 크기의 난수 데이터를 받을 수 있다. C 프로그램에서는 일반적으로 arc4random, arc4random_bufarc4random_uniform을 사용한다.

arc4random 계열은 애플리케이션이 난수 생성기의 내부 상태와 시드 파일을 직접 관리하지 않아도 되도록 설계되었다. fork와 프로세스 수명 변화에 맞춰 내부 상태를 갱신하고, 커널 난수원과 연동한다.

arc4random_uniform은 단순한 나머지 연산에서 발생하는 모듈로 편향을 피하면서 지정한 범위의 값을 생성한다. 무작위 인덱스, 순서와 식별자를 만들 때 반복되던 잘못된 범위 변환을 줄인다.

부팅 시 충분한 엔트로피를 이어가기 위해 이전 실행에서 저장한 난수 시드가 활용될 수 있다. 시드 파일은 다음 부팅의 난수 상태에 혼합된 뒤 다시 갱신되며, 파일의 내용 하나만으로 최종 난수가 결정되지는 않는다.

OpenBSD의 주소 공간 무작위화, 스택 쿠키, malloc 배치와 라이브러리 재연결도 보안 난수에 의존한다. 난수 하위 시스템의 품질은 암호화뿐 아니라 메모리 공격 완화의 예측 불가능성에도 영향을 준다.[58][59]

암호화와 키 관리

OpenBSD는 암호화를 외부 확장 기능이 아니라 기본 운영체제의 일부로 통합한다. 원격 접속, 네트워크 터널, TLS, 사용자 인증, 디스크 암호화와 패키지·업데이트 검증에 암호화 기능이 사용된다.

기본 암호화 라이브러리는 LibreSSL 계통의 libcrypto, libssl과 관련 인터페이스를 제공한다. OpenBSD 프로젝트는 OpenSSL에서 분기한 뒤 오래된 코드와 불필요한 기능을 제거하고 API와 내부 구현을 정리해 왔다.[60]

OpenSSH는 원격 로그인, 명령 실행, 파일 전송과 포트 전달에 암호화된 통신을 제공한다. 서버 호스트 키는 시스템의 신원을 나타내며, 사용자 키는 공개 키 인증에 사용된다.

개인 키는 파일 권한으로 보호되며 필요하면 암호문으로 저장할 수 있다. ssh-agent는 해독된 개인 키를 메모리에 유지하고, 클라이언트 프로그램에는 서명 작업만 제공하여 키 파일 자체를 반복해서 노출하지 않게 한다.

signify는 OpenBSD 설치 파일 세트, 패키지와 패치의 서명을 생성하고 검증하는 데 사용되는 단순한 공개 키 서명 도구다. 배포 파일을 내려받은 뒤 프로젝트가 서명한 내용과 일치하는지 확인할 수 있다.

softraid의 암호화 디스크 기능은 저장 장치 데이터를 암호화한다. 부팅과 장치 연결 과정에서 암호 또는 키 자료를 이용해 암호화 볼륨을 활성화하며, 파일 시스템은 해독된 논리 장치 위에 생성된다.

IPsec과 iked는 네트워크 계층의 암호화 터널과 키 교환을 제공한다. WireGuard 인터페이스도 커널 네트워크 구성과 함께 사용할 수 있다.

암호 키는 필요한 프로세스와 구성 요소에만 노출되도록 해야 한다. 권한 분리된 서비스에서는 키를 가진 프로세스와 외부 입력을 처리하는 프로세스를 분리하고, 제한된 서명·복호화 요청만 메시지로 전달할 수 있다.

OpenBSD는 오래되거나 안전성이 낮아진 암호 알고리즘과 프로토콜을 영구적으로 유지하기보다 기본값에서 제거하거나 지원 범위를 줄일 수 있다. 암호화 호환성보다 현재의 안전한 알고리즘과 단순한 구현을 우선하는 방향이다.

doas

doas는 허가된 사용자가 명령을 다른 사용자 권한으로 실행할 수 있게 하는 도구다. 일반적으로 관리 명령을 root 권한으로 실행하는 데 사용되며, 작은 코드와 간결한 설정 형식을 지향한다.

정책은 /etc/doas.conf에 기록한다. 규칙은 허용 또는 거부 여부, 실행을 요청한 사용자, 대상 사용자, 명령과 인수를 조건으로 지정할 수 있다.

permit 규칙은 조건에 맞는 명령 실행을 허용하고, deny 규칙은 이를 거부한다. 여러 규칙이 일치할 경우 매뉴얼에 정의된 순서에 따라 최종 정책을 결정한다.

as를 사용하면 root 이외의 사용자로 실행하도록 지정할 수 있다. cmdargs를 이용하면 허용되는 실행 파일과 인수를 제한할 수 있어, 사용자가 임의의 root 명령을 실행하지 않고 특정 관리 작업만 수행하도록 구성할 수 있다.

nopass는 인증 없이 실행하도록 허용하고, persist는 일정 기간 인증 결과를 유지한다. 이러한 옵션은 사용 환경과 필요한 보안 수준에 따라 선택적으로 적용한다.

keepenvsetenv는 대상 명령에 전달할 환경 변수를 제어한다. 특권 프로그램에서 환경 변수는 라이브러리 검색 경로와 프로그램 동작을 바꿀 수 있으므로, 필요한 값만 명시적으로 유지하는 방식이 사용된다.

설정 파일은 root가 소유하고 일반 사용자가 수정할 수 없어야 한다. 정책을 변경한 뒤에는 doas -C로 문법과 특정 명령이 허용되는지 검사할 수 있다.

doas는 root 계정이나 전통적인 UNIX 권한 모델을 대체하지 않는다. 관리자가 필요한 권한 위임 규칙을 좁고 읽기 쉬운 형태로 정의하여, 사용자가 지속적인 root 셸을 사용하는 상황을 줄이는 도구다.[61][62]

보안 업데이트

OpenBSD는 정식 릴리스에서 발견된 보안 문제와 중요한 신뢰성 오류를 errata와 패치로 공개한다. 각 항목에는 영향을 받는 구성 요소, 문제의 성격, 수정 시점과 적용 방법이 기록된다.[63]

기본 시스템의 소스 패치는 unified diff 형식으로 배포되며 signify로 서명된다. 사용자는 패치를 검증한 뒤 소스 트리에 적용하여 수정된 커널이나 사용자 공간 구성 요소를 다시 빌드할 수 있다.

지원되는 정식 릴리스에서는 syspatch가 보안·신뢰성 수정의 바이너리 패치를 내려받아 적용한다. 시스템은 설치된 패치와 사용 가능한 패치를 비교하고, 필요한 파일을 검증한 뒤 교체한다.

syspatch는 OpenBSD 기본 시스템을 대상으로 한다. 포트와 패키지로 설치한 외부 소프트웨어는 별도의 패키지 저장소와 pkg_add -u를 통해 갱신해야 한다.

패치는 -stable 소스 브랜치에도 반영된다. 소스에서 시스템을 유지하는 사용자는 해당 브랜치를 갱신하여 수정 사항이 포함된 커널과 사용자 공간을 빌드할 수 있다.

-current는 다음 릴리스를 개발하는 소스 트리이므로 정식 릴리스용 syspatch 체계와 다르게 관리된다. -current 사용자는 대응하는 최신 스냅샷과 패키지로 시스템 전체를 함께 갱신해야 한다.[64]

기본 시스템 패치가 커널, 라이브러리나 장기간 실행되는 데몬을 변경하면 재부팅 또는 서비스 재시작이 필요할 수 있다. 패치 적용 도구의 성공만 확인하는 것보다 수정된 코드가 실제 실행 중인지 확인해야 한다.

새로운 정식 릴리스로의 업그레이드는 sysupgrade와 설치 램디스크를 통해 수행할 수 있다. 이는 같은 릴리스 안에서 개별 패치를 적용하는 syspatch와 달리 커널, 기본 파일 세트와 설정 변경을 다음 릴리스로 전환한다.

OpenBSD의 보안 업데이트 구조는 기본 시스템과 외부 패키지를 구분한다. 커널과 기본 라이브러리의 패치가 제3자 웹 브라우저나 데이터베이스까지 수정하지 않으며, 패키지 업데이트 역시 기본 커널을 대체하지 않는다. 관리자는 두 계층을 각각 최신 상태로 유지해야 한다.[65]

네트워크 구조

OpenBSD의 네트워크 구조는 커널에 통합된 IPv4·IPv6 프로토콜 스택, 소켓 인터페이스, 라우팅 테이블, PF 패킷 필터와 다양한 물리·가상 네트워크 인터페이스로 구성된다. 사용자 공간에서는 ifconfig, route, netstat, pfctl과 라우팅·터널링 데몬이 커널의 네트워크 상태를 설정하고 관리한다.

네트워크 기능은 서로 독립된 외부 패키지를 조합하는 방식보다 기본 시스템 안에서 함께 개발되는 구조를 따른다. PF는 커널에서 패킷 필터링과 상태 추적을 수행하고, pfctl은 규칙을 적재한다. bgpd, ospfd, ospf6dripd 같은 데몬은 라우팅 프로토콜을 처리한 뒤 커널 라우팅 테이블에 경로를 반영한다.

물리 인터페이스 외에도 bridge, vether, vlan, trunk, carp, pfsync, tun, tap, wg, gif, gre, vxlan과 같은 가상 인터페이스가 커널의 공통 인터페이스 모델에 통합된다. 이에 따라 방화벽, 라우터, 무선 접속 장치, 가상 사설망 게이트웨이, 가상 머신 네트워크와 고가용성 클러스터를 같은 관리 체계에서 구성할 수 있다.

OpenBSD는 네트워크 기능의 성능뿐 아니라 입력 검증과 권한 격리를 중요하게 다룬다. 커널의 패킷 처리 경로는 비정상적인 헤더와 상태를 검사하고, 사용자 공간 데몬은 역할별 프로세스 분리, 전용 사용자, pledgeunveil을 이용해 침해 시 접근 범위를 줄인다.

네트워크 스택

OpenBSD의 네트워크 스택은 이더넷과 무선 LAN 같은 링크 계층에서 IPv4·IPv6, TCP·UDP와 응용 프로그램의 소켓 인터페이스로 이어지는 계층형 구조다. 네트워크 인터페이스에서 수신된 프레임은 해당 링크 계층과 프로토콜 처리기를 거쳐 소켓으로 전달되거나 다른 인터페이스로 전달된다.

사용자 공간 프로그램은 socket, bind, connect, listen, accept, sendmsgrecvmsg 등의 시스템 호출을 통해 네트워크 기능을 사용한다. 각 소켓에는 주소 계열, 프로토콜, 로컬·원격 주소와 프로토콜별 제어 상태가 연결된다.

IPv4와 IPv6는 주소, 라우팅, 단편화, 재조립, 오류 처리와 전달 기능을 제공한다. TCP는 연결 설정, 순서 보장, 재전송, 흐름 제어와 혼잡 제어를 담당하고, UDP는 연결 설정 없이 데이터그램을 전달한다.

링크 계층 주소 해석에는 IPv4의 ARP와 IPv6의 Neighbor Discovery가 사용된다. 커널은 인접 호스트의 네트워크 주소와 링크 계층 주소의 대응 관계를 캐시에 저장하고, 필요한 경우 요청을 전송하여 주소를 확인한다.

네트워크 입력은 인터페이스 드라이버에서 시작된다. 드라이버는 수신된 패킷을 커널 패킷 버퍼에 넣고 상위 프로토콜 계층으로 전달한다. 송신 시에는 라우팅 결정, PF 처리와 링크 계층 캡슐화를 거쳐 장치 드라이버의 송신 큐로 넘어간다.

OpenBSD의 패킷 데이터는 주로 mbuf 구조를 통해 전달된다. 하나의 패킷은 여러 mbuf가 연결된 형태로 표현될 수 있으며, 프로토콜 헤더와 데이터, 인터페이스·PF 관련 메타데이터를 함께 보관한다.

호스트가 목적지인 패킷은 로컬 프로토콜 처리로 전달되고, IP forwarding이 활성화된 시스템에서 다른 목적지를 가진 패킷은 라우팅 테이블을 조회하여 다음 인터페이스로 전달될 수 있다. IPv4와 IPv6 전달 기능은 별도로 활성화하고 제어한다.

OpenBSD는 여러 개의 독립된 라우팅 도메인을 지원한다. 인터페이스와 프로세스를 특정 routing domain에 배치하면 각각 별도의 라우팅 테이블을 사용하게 할 수 있다. route -T, ifconfig rdomainroute -T exec 등을 통해 이를 관리한다.[66]

네트워크 스택은 전통적으로 커널의 큰 잠금에 의존했지만, 이후 인터페이스와 프로토콜 처리 경로를 세분화된 잠금과 CPU별 처리 구조로 옮기는 작업이 진행되었다. 이를 통해 여러 CPU가 서로 다른 네트워크 작업을 병렬로 처리할 수 있는 범위가 확대되었다.[67]

PF

PF는 OpenBSD의 패킷 필터이자 상태 기반 방화벽 체계다. 커널에서 패킷을 검사하고, 사용자 공간의 pfctl/etc/pf.conf에 작성된 규칙을 해석하여 커널에 적재한다.

PF는 2001년 IPFilter를 대체하기 위해 개발되었으며 OpenBSD 3.0부터 기본 시스템에 포함되었다. 이후 필터링뿐 아니라 네트워크 주소 변환, 패킷 정규화, 리디렉션, 상태 추적, 트래픽 우선순위와 고가용성 방화벽 구성으로 범위가 확장되었다.

PF 규칙은 일반적으로 패킷을 통과시키는 pass와 차단하는 block을 중심으로 작성한다. 방향, 인터페이스, 주소 계열, 프로토콜, 출발지·목적지 주소와 포트, TCP 플래그와 여러 패킷 속성을 조건으로 사용할 수 있다.

규칙은 위에서 아래로 평가되며, 일반적인 필터 규칙에서는 마지막으로 일치한 규칙이 결과를 결정한다. quick이 지정된 규칙은 일치하는 즉시 평가를 끝내므로 명시적인 예외와 우선 규칙을 표현할 수 있다.

인터페이스 이름, 주소와 네트워크 집합은 매크로와 테이블로 정리할 수 있다. 테이블은 많은 주소를 효율적으로 관리하며 pfctl을 이용해 전체 규칙을 다시 적재하지 않고도 항목을 추가하거나 제거할 수 있다.

앵커는 PF 규칙을 계층적인 하위 규칙 집합으로 분리한다. 데몬이나 관리 도구는 지정된 앵커 아래에 동적 규칙을 추가할 수 있으며, 기본 방화벽 정책과 서비스별 동적 정책을 분리할 수 있다.

PF는 필터 규칙을 적재할 때 문법과 의미를 검사한다. pfctl -n을 사용하면 실제 적용 없이 규칙을 검증할 수 있고, pfctl -f로 규칙을 적재하며, pfctl -sr, -sn, -ss 등으로 현재 규칙과 상태를 확인한다.[68]

PF는 OpenBSD의 GENERIC 커널에 포함된 기본 기능이다. 외부 커널 모듈이나 별도 패키지를 설치하지 않아도 사용할 수 있으며 커널 네트워크 스택, 라우팅, 인터페이스와 함께 개발된다.[69]

패킷 필터링과 상태 추적

PF는 각 패킷을 독립적으로 검사하는 무상태 필터링과 연결의 흐름을 기억하는 상태 기반 필터링을 모두 지원한다. 일반적인 pass 규칙은 기본적으로 상태를 생성하므로 이후 같은 연결에 속하는 패킷을 전체 규칙과 다시 비교하지 않고 상태표를 통해 처리할 수 있다.

상태 항목에는 출발지·목적지 주소와 포트, 프로토콜, 인터페이스, TCP 상태, 패킷·바이트 수와 만료 시간이 기록된다. NAT나 리디렉션이 적용되면 변환 전후의 주소 정보도 상태에 연결된다.

TCP 상태 추적은 연결 설정과 종료 과정, 순서 번호와 플래그를 확인한다. 정상적인 연결 흐름에서 벗어난 패킷이나 현재 상태와 맞지 않는 패킷을 거부하여 단순한 주소·포트 필터보다 엄격하게 연결을 검사할 수 있다.

UDP와 ICMP처럼 TCP와 동일한 연결 상태를 갖지 않는 프로토콜도 일정 시간 동안 통신 흐름을 상태로 추적한다. 요청과 응답의 주소·포트 관계를 기록하여 반환 트래픽을 허용할 수 있다.

keep state, modulate statesynproxy state를 통해 상태 생성 방식을 조정할 수 있다. modulate state는 TCP 초기 순서 번호를 변환하고, synproxy state는 PF가 서버 대신 TCP 연결의 초기 핸드셰이크를 확인한 뒤 실제 서버로 연결을 이어준다.

상태 정책은 인터페이스에 결합된 상태와 모든 인터페이스에서 일치할 수 있는 상태로 나눌 수 있다. 비대칭 라우팅이나 여러 경로를 사용하는 구성에서는 상태 정책과 패킷이 실제로 통과하는 인터페이스를 함께 고려해야 한다.

max, max-src-states, max-src-conn, max-src-conn-rate 등의 제한은 규칙과 출발지별 상태 수와 연결 생성 속도를 제한한다. 과도한 연결을 만드는 출발지를 overload 테이블에 넣어 후속 트래픽을 차단할 수도 있다.

상태표는 pfctl -ss로 확인하고 선택적으로 제거할 수 있다. 고가용성 구성에서는 pfsync가 상태 정보를 다른 방화벽으로 복제하여 장치 전환 뒤에도 기존 연결을 유지할 수 있게 한다.[70]

네트워크 주소 변환

PF는 IPv4 네트워크 주소 변환과 포트 변환을 필터 규칙과 같은 규칙 체계에서 처리한다. 내부 주소를 외부 주소로 바꾸는 출발지 NAT, 외부 연결의 목적지를 내부 서버로 바꾸는 리디렉션과 양쪽 주소를 함께 바꾸는 변환을 구성할 수 있다.

출발지 NAT는 사설 네트워크의 여러 호스트가 방화벽의 공인 주소를 공유하여 외부 네트워크에 연결하는 데 사용된다. PF는 내부 연결마다 변환된 주소와 포트의 대응 관계를 상태표에 기록하고 반환 패킷을 원래 내부 호스트로 되돌린다.

nat-to는 패킷의 출발지 주소를 지정된 주소 또는 인터페이스 주소로 변환한다. 동적으로 주소를 받는 외부 인터페이스에서는 해당 인터페이스의 현재 주소를 참조하는 문법을 사용할 수 있다.

rdr-to는 목적지 주소나 포트를 다른 호스트와 서비스로 변경한다. 외부 인터페이스의 특정 포트를 내부 웹 서버로 전달하거나 로컬 프록시로 투명하게 리디렉션하는 데 사용할 수 있다.

binat-to는 하나의 내부 주소와 하나의 외부 주소 사이에 양방향 1대1 변환을 구성한다. 내부에서 외부로 나가는 트래픽과 외부에서 내부로 들어오는 트래픽에 서로 반대 방향의 주소 변환이 적용된다.

PF의 주소 변환은 상태 추적과 결합된다. 첫 패킷에 적용된 변환은 해당 상태에 저장되며 이후 패킷과 반환 트래픽에 일관되게 적용된다.

주소 풀을 사용하면 여러 외부 주소에 연결을 분배할 수 있다. round-robin, random, source-hashsticky-address 등의 방식을 사용해 주소 선택 정책을 조정할 수 있다.

NAT는 내부 네트워크의 주소를 외부에서 직접 보이지 않게 할 수 있지만 그 자체가 완전한 접근 제어는 아니다. OpenBSD에서는 주소 변환과 pass·block 필터 정책을 함께 정의하여 실제로 허용할 연결을 결정한다.[71]

트래픽 제어와 대기열 관리

OpenBSD는 PF 규칙과 네트워크 인터페이스의 대기열 기능을 이용해 패킷의 우선순위와 전송 순서를 제어한다. 링크의 전체 대역폭을 임의로 늘리지는 못하지만, 혼잡할 때 어떤 트래픽을 먼저 보내고 어떤 흐름이 대기하도록 할지를 결정할 수 있다.

PF의 set prio와 규칙별 prio는 패킷의 우선순위를 지정한다. 일반 트래픽과 낮은 지연이 필요한 DNS, SSH, 음성 또는 제어 트래픽에 서로 다른 우선순위를 부여할 수 있다.

패킷에는 들어올 때의 우선순위와 나갈 때의 우선순위를 따로 지정할 수 있다. 응답 트래픽의 우선순위를 별도로 높이면 느린 업로드 링크에서 ACK와 제어 패킷이 대용량 데이터 뒤에 오래 대기하는 현상을 줄일 수 있다.

인터페이스의 전송 대기열은 여러 흐름 사이에서 패킷을 배분한다. OpenBSD는 공정 대기열과 흐름 기반 관리 기능을 통해 하나의 대량 전송이 전체 링크 대기열을 독점하는 것을 완화한다.

set queue 또는 규칙의 대기열 지정은 일치한 패킷을 특정 인터페이스 대기열에 넣는다. 서비스 종류, 주소, 포트와 PF 태그에 따라 트래픽을 분류할 수 있다.

대기열 관리의 목적은 단순히 특정 프로그램의 속도를 제한하는 것만이 아니다. 링크가 포화될 때 대기 시간이 과도하게 늘어나는 버퍼블로트를 줄이고, 상호작용형 통신과 제어 패킷에 예측 가능한 지연을 제공하는 데에도 사용된다.

PF의 set tosset prio는 IP 헤더 또는 커널 내부 우선순위 정보를 변경할 수 있다. 다른 라우터와 호스트가 DSCP·서비스 등급 정보를 사용하는 환경에서는 전체 경로의 정책과 함께 구성해야 한다.

수신 트래픽은 이미 외부 링크를 통과해 도착했으므로 방화벽에서 직접 외부 송신 속도를 제어할 수 없다. 수신 측에서 지연·손실을 유도하거나 내부로 전달되는 속도를 조절할 수 있지만, 실제 병목 링크에 가까운 송신 방향에서 대기열을 관리하는 편이 일반적으로 효과적이다.[72]

라우팅

OpenBSD 커널은 목적지 주소에 따라 다음 홉과 출력 인터페이스를 선택하는 라우팅 테이블을 유지한다. 직접 연결된 네트워크, 기본 경로, 정적 경로와 라우팅 데몬이 학습한 동적 경로가 같은 커널 라우팅 구조에 기록된다.

route는 경로를 추가·삭제하고 라우팅 테이블을 조회하는 관리 명령이다. route show 또는 netstat -rn으로 현재 경로와 게이트웨이, 인터페이스, 우선순위와 플래그를 확인할 수 있다.

경로는 목적지 접두사 길이를 기준으로 가장 구체적인 항목이 선택된다. 같은 접두사에 여러 경로가 존재하면 우선순위, 경로 상태와 다중 경로 정책이 선택에 영향을 준다.

정적 기본 게이트웨이는 부팅 설정에서 지정할 수 있으며, 인터페이스의 직접 연결 경로는 주소가 설정될 때 자동으로 생성된다. DHCP와 IPv6 라우터 광고를 사용하는 경우 동적으로 경로가 제안되고 갱신될 수 있다.

OpenBSD는 routing domain과 다중 라우팅 테이블을 지원한다. 서로 다른 고객, 가상 머신, VPN 또는 관리망을 별도 라우팅 도메인에 배치하여 같은 주소 공간을 사용하더라도 경로를 분리할 수 있다.

rtable은 라우팅 테이블 번호를 지정하고, rdomain은 인터페이스와 소켓이 속한 라우팅 도메인을 나타낸다. PF 규칙은 rtable 또는 route-to 등을 사용하여 특정 트래픽의 라우팅 경로에 영향을 줄 수 있다.

route-to는 PF 규칙과 일치한 패킷을 지정한 인터페이스와 게이트웨이로 전달하고, reply-to는 연결의 응답 경로를 지정한다. 여러 인터넷 회선이나 비대칭 경로가 있는 환경에서 정책 기반 라우팅을 구성할 때 사용된다.

동적 라우팅에는 OpenBGPD, ospfd, ospf6dripd 등이 사용된다. 이들 데몬은 네트워크 이웃과 경로 정보를 교환하고, 선택한 경로를 커널의 Forwarding Information Base에 설치한다.

OpenBGPD는 인터넷 규모의 BGP 라우팅을 제공하며 경로 필터, RPKI 검증, 다중 라우팅 도메인과 여러 정책 기능을 지원한다. OpenOSPFD와 OpenOSPF6D는 각각 IPv4와 IPv6 내부 라우팅 환경에서 링크 상태 정보를 교환한다.

커널은 실제 패킷 전달에 필요한 경로만 사용하고, 복잡한 라우팅 프로토콜 상태와 정책 계산은 사용자 공간 데몬이 담당한다. 이 분리는 네트워크 입력을 해석하는 복잡한 코드가 커널 안에서 실행되는 범위를 줄인다.[73][74]

가상 사설망

OpenBSD는 IPsec, IKEv2, WireGuard와 여러 터널 인터페이스를 기본 시스템에서 제공한다. VPN은 암호화 프로토콜과 키 교환 데몬, 가상 인터페이스, 라우팅과 PF 정책을 함께 구성하여 구축한다.

IPsec은 IP 계층에서 패킷을 인증하거나 암호화한다. 커널은 Security Association과 Security Policy를 바탕으로 패킷에 ESP 처리를 적용하고, 사용자 공간의 iked 또는 isakmpd가 상대와 키를 협상한다.

iked는 IKEv2 프로토콜을 구현한다. 인증서, 공개 키, 사전 공유 키와 EAP 기반 인증을 사용할 수 있으며, 협상된 키와 정책을 커널의 IPsec 하위 시스템에 설치한다.

경로 기반 IPsec 구성에서는 sec 계열 인터페이스를 사용해 암호화된 연결을 일반 네트워크 인터페이스처럼 라우팅과 PF 규칙에 연결할 수 있다. 정책 기반 구성에서는 목적지와 출발지, 프로토콜에 따라 IPsec 정책을 적용한다.

wg 인터페이스는 WireGuard 프로토콜을 구현한다. 각 동료의 공개 키, 허용 주소와 원격 끝점을 설정하고, 일반 인터페이스처럼 IP 주소와 경로를 배치한다.

WireGuard의 allowed-ips는 동료에게 보낼 수 있는 목적지와 해당 동료에게서 허용할 출발지 범위를 결정한다. 암호화된 터널을 만들더라도 실제 접근 범위와 전달 정책은 라우팅 및 PF 규칙과 함께 구성해야 한다.

gif는 IP 안에 IPv4 또는 IPv6 패킷을 캡슐화하고, gre는 GRE 터널을 제공한다. 이들은 자체적으로 강한 암호화를 제공하지 않으므로 암호화가 필요하면 IPsec과 결합하거나 신뢰된 경로에서 사용한다.

tun은 사용자 공간 프로그램과 IP 패킷을 교환하는 계층 3 인터페이스이며, tap은 이더넷 프레임을 교환하는 계층 2 인터페이스다. 외부 VPN 프로그램과 가상 머신 네트워크가 커널 네트워크 스택에 연결되는 데 사용할 수 있다.

VPN 인터페이스는 별도의 특수 방화벽 체계가 아니라 일반 PF 규칙, routing domain과 인터페이스 그룹에 통합된다. 암호화 전후의 트래픽이 어떤 인터페이스에 나타나는지 고려하여 필터 정책을 구성한다.[75][76]

무선 네트워크

OpenBSD의 무선 네트워크 기능은 커널의 IEEE 802.11 계층, 장치별 무선 드라이버와 사용자 공간의 ifconfig·hostname.if 설정으로 구성된다. 별도의 범용 연결 관리자 없이도 기본 시스템만으로 무선 네트워크에 연결할 수 있다.

무선 인터페이스는 유선 인터페이스와 같은 ifconfig 명령으로 관리하지만, 네트워크 이름인 nwid, 암호, 채널, 액세스 포인트와 보안 프로토콜 같은 추가 속성을 가진다.

일반적인 클라이언트 구성에서는 /etc/hostname.인터페이스에 네트워크 이름과 WPA 키, 주소 자동 설정을 기록한다. 부팅 과정에서 netstart가 해당 설정을 읽어 인터페이스를 구성한다.

여러 무선 네트워크를 이동하며 사용할 때는 join 목록을 설정할 수 있다. 커널은 사용 가능한 네트워크 가운데 설정과 일치하는 항목을 선택하여 연결하고, 우선순위와 신호 상태에 따라 다른 네트워크로 전환할 수 있다.

WPA2·WPA3 Personal 환경에서는 사전 공유 키를 사용하며, 암호문 자체를 설정 파일에 직접 보관하는 대신 wpakey의 파생 결과를 저장할 수 있다. 설정 파일의 읽기 권한도 제한해야 한다.

IEEE 802.1X와 기업용 무선 인증은 wpa_supplicant 등의 추가 프로그램이 필요한 경우가 있다. 지원 범위는 사용되는 인증 방식과 드라이버에 따라 달라질 수 있다.

일부 무선 장치는 장치 내부에서 실행되는 펌웨어를 필요로 한다. OpenBSD는 재배포할 수 있는 펌웨어를 fw_update로 설치하며, 커널 드라이버 자체는 공개된 소스 코드로 유지한다.

무선 장치의 지원 수준은 칩셋과 드라이버에 따라 다르다. 같은 제품명으로 판매되는 장치도 하드웨어 개정에 따라 다른 칩셋을 사용할 수 있으므로, 실제 PCI·USB 식별자와 해당 OpenBSD 드라이버의 매뉴얼을 확인해야 한다.

OpenBSD는 일부 지원 장치에서 액세스 포인트 모드도 제공한다. 무선 인터페이스를 AP로 구성하고 DHCP, 라우팅과 PF를 결합하면 무선 라우터나 보안 게이트웨이로 사용할 수 있다.[77][78]

네트워크 가상화

OpenBSD의 네트워크 가상화는 가상 인터페이스, 브리지, VLAN, routing domain과 PF를 결합하여 하나의 호스트 안에 여러 논리 네트워크를 구성하는 방식이다.

bridge 인터페이스는 여러 이더넷 인터페이스를 하나의 계층 2 브로드캐스트 도메인으로 연결한다. 물리 인터페이스, vether, tap과 가상 머신 인터페이스를 같은 브리지에 넣을 수 있다.

브리지는 수신 프레임의 출발지 MAC 주소를 학습하고, 목적지 주소가 어느 포트에 있는지 알면 해당 포트로만 전달한다. 알 수 없는 주소와 브로드캐스트·멀티캐스트 프레임은 필요한 멤버 포트로 확산한다.

vether는 실제 하드웨어가 없는 가상 이더넷 인터페이스다. 호스트가 브리지 네트워크에 직접 참여하도록 하거나, 가상 머신과 호스트 사이의 논리 게이트웨이를 구성할 때 사용한다.

vlan은 하나의 물리 링크에서 IEEE 802.1Q 태그로 여러 논리 계층 2 네트워크를 분리한다. 각 VLAN 인터페이스는 별도의 IP 주소, PF 정책과 routing domain을 가질 수 있다.

trunk는 여러 물리 인터페이스를 하나의 논리 인터페이스로 묶는다. 장애 조치, 부하 분산과 LACP 같은 프로토콜을 사용하여 링크 가용성과 처리량을 조정할 수 있다.

pair 인터페이스는 서로 직접 연결된 가상 이더넷 인터페이스 쌍을 제공한다. 두 개의 라우팅 도메인이나 브리지 사이를 명시적으로 연결하고 PF를 적용하는 구성에 활용할 수 있다.

vxlan은 UDP 네트워크 위에 계층 2 네트워크를 캡슐화한다. 서로 다른 물리 위치의 가상 네트워크를 확장할 수 있지만, 암호화를 자체 제공하는 기능은 아니므로 신뢰 경계와 터널 보호를 별도로 고려한다.

routing domain은 계층 3 경로를 분리하고, 브리지와 VLAN은 계층 2 영역을 나눈다. 두 기능을 결합하면 가상 머신 그룹, 고객망, 관리망과 외부망이 서로 다른 경로와 방화벽 정책을 사용하게 할 수 있다.

vmd가 생성한 가상 머신 네트워크 인터페이스는 tap 또는 vether·브리지 구성과 연결할 수 있다. 호스트가 NAT 라우터 역할을 하거나 가상 머신을 물리 LAN에 직접 연결하는 구조를 선택할 수 있다.[79][80][81]

고가용성과 장애 조치

OpenBSD는 CARP, pfsync, PF와 링크 집계 기능을 이용해 방화벽과 라우터의 장애 조치 구성을 만들 수 있다. 여러 장치가 하나의 논리적 게이트웨이 주소와 방화벽 상태를 공유하고, 활성 장치가 중단되면 다른 장치가 역할을 이어받는다.

CARP는 여러 호스트가 하나 이상의 가상 IP 주소를 공유하게 한다. 각 CARP 그룹에는 가상 호스트 식별자와 인증 정보가 설정되며, 현재 master인 장치가 가상 주소에 대한 트래픽을 처리한다.

master는 주기적으로 CARP 광고를 전송한다. backup 장치가 일정 시간 광고를 받지 못하면 우선순위와 상태에 따라 master로 전환하고 가상 IP 주소의 역할을 인계한다.

advbaseadvskew는 광고 간격과 우선순위에 영향을 준다. 낮은 advskew를 가진 정상 장치가 일반적으로 master가 되며, carpdemote 값은 인터페이스·서비스 장애를 전체 우선순위에 반영할 수 있다.

가상 IP 주소만 인계하면 기존 상태 기반 연결은 새 방화벽의 상태표에 존재하지 않는다. pfsync는 PF 상태 생성·수정·삭제 정보를 다른 방화벽에 전달하여 장치 전환 뒤에도 기존 TCP·UDP 연결을 가능한 한 유지한다.

pfsync 트래픽은 상태와 연결 정보를 포함하므로 신뢰된 전용 동기화 네트워크를 사용하는 것이 일반적이다. 물리적으로 분리할 수 없다면 해당 링크의 접근 제어와 보호를 별도로 구성해야 한다.

CARP와 pfsync는 서로 다른 기능이다. CARP는 주소와 master 역할을 전환하고, pfsync는 PF 상태를 복제한다. 고가용성 방화벽에서는 일반적으로 두 기능을 함께 사용한다.

ifstated는 인터페이스와 CARP 상태 변화를 관찰하고 명령을 실행할 수 있다. 외부 회선이나 상위 경로가 끊어졌을 때 CARP 우선순위를 낮추거나 라우팅·서비스 상태를 변경하는 데 활용할 수 있다.

trunk의 failover 또는 LACP는 개별 호스트의 물리 링크 장애를 처리한다. CARP가 호스트 단위의 장애 조치를 담당한다면 trunk는 하나의 호스트 안에서 여러 링크의 가용성을 높이는 역할을 한다.

동적 라우팅 데몬과 CARP를 결합하면 단순한 기본 게이트웨이 전환을 넘어 라우팅 인접 관계와 경로 광고도 장애 상태에 따라 조정할 수 있다. 네트워크 전체가 새 경로를 선택하는 시간과 PF 상태 전환 시간을 함께 고려해야 한다.[82][83][84]

네트워크 서비스의 권한 분리

OpenBSD의 네트워크 서비스는 외부 입력을 처리하는 복잡한 코드와 높은 권한이 필요한 작업을 서로 다른 프로세스로 분리하는 구조를 널리 사용한다. 네트워크 데몬 하나가 모든 파일, 소켓, 인증 정보와 시스템 변경 권한을 계속 보유하지 않게 하기 위한 설계다.

일반적인 구조에서는 부모 또는 감시 프로세스가 root 권한으로 시작하여 보호된 포트, 라우팅 소켓, 키와 설정 파일을 연다. 이후 프로토콜 해석, 네트워크 입력과 대부분의 상태 처리는 전용 사용자로 실행되는 비권한 프로세스에 맡긴다.

프로세스 사이의 통신에는 제한된 메시지 형식이 사용된다. 비권한 프로세스가 높은 권한의 부모에게 임의의 함수 실행을 요청하는 대신, 사전에 정의된 메시지와 검증된 인수만 전달할 수 있다.

OpenSSH의 서버는 인증 전 네트워크 입력을 처리하는 프로세스, 권한이 필요한 감시 프로세스와 인증 후 사용자 세션을 분리한다. 인증되지 않은 원격 입력을 해석하는 코드가 직접 전체 root 권한을 갖지 않도록 한다.

OpenBGPD는 프로토콜 엔진, 경로 결정 엔진과 부모 프로세스를 분리한다. BGP 메시지를 해석하고 경로를 계산하는 부분과 커널 라우팅 테이블·보호된 자원에 접근하는 부분이 제한된 메시지 인터페이스로 연결된다.

OpenSMTPD, relayd, iked, ntpd와 여러 DHCP 관련 프로그램도 역할별 프로세스, 전용 사용자와 권한 폐기를 사용한다. 각 데몬의 실제 구성은 기능에 따라 다르지만 외부 입력을 처리하는 부분의 권한을 줄이는 공통 방향을 따른다.

프로세스는 초기화가 끝난 뒤 필요 없는 파일 디스크립터를 닫고 사용자·그룹 권한을 낮춘다. chroot, pledgeunveil을 함께 적용하여 시스템 호출 종류, 파일 경로와 실행 가능한 후속 작업을 추가로 제한할 수 있다.

권한 분리는 커널 네트워크 스택과 사용자 공간 프로토콜 구현의 분리에도 나타난다. BGP, OSPF와 IKE처럼 복잡하고 자주 변경되는 프로토콜 처리는 사용자 공간 데몬이 담당하고, 커널은 패킷 전달과 설치된 경로·암호화 상태를 적용한다.

이 구조는 네트워크 데몬의 취약점을 제거하지는 않는다. 대신 하나의 입력 파서나 프로토콜 처리기가 침해되었을 때 공격자가 얻는 사용자 ID, 볼 수 있는 파일, 사용할 수 있는 시스템 호출과 커널 변경 권한을 줄인다.

OpenBSD는 권한 분리를 일회성 설계가 아니라 계속 개선하는 과정으로 다룬다. 기존 데몬도 역할을 더 세분화하거나 프로세스 사이의 메시지를 단순화하고, pledge·unveil 정책을 좁히는 방향으로 수정된다.[85][86]

파일 시스템과 저장 장치

OpenBSD의 저장 장치 구조는 물리 장치를 제어하는 장치 드라이버, 디스크를 운영체제용 영역으로 나누는 파티션·디스크레이블, 여러 장치를 결합하거나 암호화하는 softraid, 그리고 파일과 디렉터리를 저장하는 파일 시스템 계층으로 이루어진다.

저장 장치는 일반적으로 sd0, sd1과 같은 디스크 장치로 커널에 연결된다. 실제 장치가 SATA SSD, NVMe SSD, USB 메모리, 가상 디스크 또는 하드웨어 RAID 논리 볼륨이더라도 OpenBSD의 SCSI 계층을 거쳐 sd 장치로 나타날 수 있다. 일부 전통적인 ATA 장치는 wd 계열 이름을 사용할 수 있다.

하나의 물리 디스크에는 플랫폼의 부팅 규격에 따른 외부 파티션 구조와 OpenBSD 내부의 디스크레이블이 함께 존재할 수 있다. amd64와 arm64 시스템에서는 GPT 또는 MBR 파티션 안에 OpenBSD 영역을 만들고, 그 안을 다시 a부터 p까지의 디스크레이블 파티션으로 나누는 방식이 일반적이다.

OpenBSD의 기본 로컬 파일 시스템은 FFS 계통이며, 현대 설치에서는 대부분 FFS2가 사용된다. 디스크 중복화와 암호화는 별도의 파일 시스템보다 softraid가 생성하는 논리 디스크 계층에서 처리되고, 그 위에 다시 디스크레이블과 파일 시스템을 구성한다.

OpenBSD 저장 장치 구성 흐름
  1. 물리 디스크 또는 가상 디스크
  2. 장치 드라이버와 SCSI 디스크 계층
  3. GPT·MBR 등 플랫폼 파티션 구조
  4. OpenBSD 디스크레이블
  5. 선택적으로 softraid RAID·CRYPTO 볼륨
  6. FFS2 또는 다른 파일 시스템
  7. 마운트 지점과 디렉터리 트리

파일 시스템 구조

OpenBSD는 하나의 루트 디렉터리 /에서 시작하는 계층형 파일 시스템 이름 공간을 사용한다. 여러 디스크와 파티션, 메모리 파일 시스템과 네트워크 파일 시스템은 각각 특정 디렉터리에 마운트되어 하나의 디렉터리 트리로 결합된다.

커널은 VFS 계층을 통해 서로 다른 파일 시스템을 공통 인터페이스로 처리한다. 파일 열기, 읽기, 쓰기, 디렉터리 탐색과 속성 조회는 공통 vnode 연산으로 전달되고, FFS·NFS와 각 파일 시스템 구현이 실제 저장 형식에 맞게 처리한다.

루트 파일 시스템은 부팅 과정에서 먼저 마운트된다. 이후 /etc/fstab에 기록된 설정과 부팅 스크립트에 따라 /usr, /home, /var, /tmp와 다른 파일 시스템이 추가로 마운트될 수 있다.

OpenBSD 설치 프로그램은 하나의 루트 파티션만 사용하는 구성도 지원하지만, 기본 자동 배치는 여러 디렉터리를 별도 파티션으로 나눌 수 있다. /home, /tmp, /usr, /usr/local, /usr/src, /var 등을 분리하면 공간 고갈과 파일 시스템 손상의 영향을 제한하고 마운트 옵션을 디렉터리 용도에 맞게 적용할 수 있다.

예를 들어 사용자 파일이 위치한 /home에는 set-user-ID 실행을 막는 nosuid와 장치 파일 해석을 막는 nodev를 적용할 수 있다. 실행 파일이 필요하지 않은 데이터 영역에는 noexec도 적용할 수 있다. 이러한 분리는 디스크 공간 관리뿐 아니라 보안 경계를 구성하는 수단이다.

마운트된 파일 시스템 정보는 mount 또는 df로 확인할 수 있다. mount는 장치와 마운트 지점, 옵션을 보여주고, df는 전체·사용·남은 공간과 inode 사용량을 표시한다.

/etc/fstab에는 장치, 마운트 지점, 파일 시스템 종류, 마운트 옵션과 검사 순서가 기록된다. 장치 이름 대신 디스크의 DUID와 파티션 문자를 사용하면 장치 검색 순서가 달라져 sd0sd1 번호가 바뀌더라도 같은 파일 시스템을 식별할 수 있다.[87]

파일 시스템은 정상적인 종료 과정에서 디스크에 동기화되고 깨끗한 상태로 표시된다. 비정상 종료 뒤에는 부팅 과정에서 fsck 또는 fsck_ffs가 메타데이터 일관성을 검사하고 필요한 복구를 수행한다.

FFS와 FFS2

FFS는 BSD 계통에서 발전한 로컬 파일 시스템으로, 파일과 디렉터리의 메타데이터를 inode에 저장하고 디스크 공간을 블록과 프래그먼트 단위로 관리한다. 파일 이름과 inode의 대응 관계는 디렉터리에 기록되며, inode는 파일 종류, 소유권, 권한, 시간 정보와 데이터 블록 위치를 보관한다.

파일 시스템은 여러 실린더 그룹으로 나뉜다. 각 그룹에는 inode, 데이터 블록과 할당 정보가 분산되어 있어 관련 파일을 가까운 위치에 배치하고, 일부 영역의 손상이 파일 시스템 전체 메타데이터에 집중되는 것을 줄인다.

FFS는 큰 블록을 사용하여 연속적인 파일 데이터를 효율적으로 읽고 쓰면서, 작은 파일의 마지막 부분에는 프래그먼트를 사용해 공간 낭비를 줄일 수 있다. 파일 시스템을 만들 때 블록 크기, 프래그먼트 크기, inode 밀도와 최적화 정책을 지정할 수 있다.

FFS2는 기존 FFS 형식을 확장한 두 번째 세대 형식이다. 64비트 블록 번호와 확장된 시간 표현을 사용하여 더 큰 파일 시스템과 넓은 시간 범위를 지원한다. OpenBSD 6.7부터 대부분의 지원 플랫폼에서 새 설치의 기본 파일 시스템으로 사용된다.[88]

FFS2의 inode는 FFS1보다 큰 주소와 시간 값을 저장할 수 있다. 이는 대용량 디스크와 2038년 이후의 시간 표현을 다루는 데 필요하다. 두 형식은 같은 FFS 계통의 명령과 커널 코드 상당 부분을 공유하지만 디스크상 메타데이터 형식은 서로 다르다.

새 파일 시스템은 newfs로 생성한다. 일반적으로 디스크레이블에 기록된 파티션 크기와 파일 시스템 매개변수를 읽어 FFS를 만들며, 필요한 경우 블록 크기와 inode 수 등을 조정할 수 있다.[89]

FFS의 일관성은 메타데이터 쓰기 순서와 파일 시스템 검사로 유지된다. 소프트 업데이트를 사용하면 관련 메타데이터가 안전한 순서로 디스크에 기록되도록 의존성을 관리하여, 모든 변경을 즉시 동기식으로 기록할 때의 성능 부담을 줄인다.

비정상 종료 뒤에는 fsck_ffs가 슈퍼블록, inode, 디렉터리 연결, 블록 할당 정보와 참조 횟수를 검사한다. 연결이 끊어진 파일이나 디렉터리는 복구 과정에서 lost+found에 배치될 수 있다.[90]

dumprestore는 FFS 파일 시스템의 inode와 파일 데이터를 백업하고 복원하는 기본 도구다. 전체 백업과 단계별 증분 백업을 만들 수 있으며, 일반적인 파일 단위 복사와 달리 FFS 구조를 이해한다.

기존 파일 시스템의 파티션을 확장한 뒤에는 growfs로 파일 시스템이 새 공간을 사용하도록 확장할 수 있다. 파일 시스템 축소는 같은 방식으로 제공되지 않으므로 초기 파티션 계획과 백업이 중요하다.

디스크 레이블

OpenBSD 디스크레이블은 하나의 디스크 또는 논리 볼륨 안을 여러 OpenBSD 파티션으로 나누고 각 파티션의 파일 시스템 종류와 위치를 기록하는 구조다. disklabel 명령으로 확인하고 편집한다.[91]

디스크레이블 파티션은 a부터 p까지의 문자로 식별된다. 장치 이름과 결합하면 sd0a, sd0d, sd0k와 같은 형태가 된다. 플랫폼과 장치 종류에 따라 일부 문자는 특별한 의미를 가진다.

a 파티션은 전통적으로 루트 파일 시스템에 사용된다. b는 스왑 파티션으로 사용하는 관례가 있으며, c는 개별 파일 시스템 파티션이 아니라 디스크 전체를 나타낸다. 따라서 c 파티션의 시작 위치와 크기를 일반 데이터 파티션처럼 변경하지 않는다.

나머지 문자는 /home, /usr, /var, RAID 구성 요소와 다른 파일 시스템에 사용할 수 있다. 각 항목에는 시작 오프셋, 크기, 파일 시스템 종류, 블록·프래그먼트 정보가 기록된다.

amd64와 같은 플랫폼에서는 GPT 또는 MBR이 디스크의 외부 분할 구조를 제공하고, OpenBSD 디스크레이블은 OpenBSD용 GPT·MBR 파티션 내부를 다시 나눈다. 이 두 계층은 목적이 다르므로 fdiskdisklabel이 각각 관리한다.

GPT에서는 EFI 시스템 파티션과 OpenBSD 파티션을 만들 수 있다. UEFI 펌웨어가 읽는 부트 로더는 EFI 시스템 파티션에 위치하고, OpenBSD 커널과 일반 파일 시스템은 OpenBSD 영역의 디스크레이블 파티션에 배치된다.

디스크레이블은 각 디스크에 기록되지만 커널은 장치를 처음 인식할 때 실제 레이블과 플랫폼 파티션 정보를 함께 해석한다. 레이블이 없거나 손상된 일부 장치에는 기본값 또는 추정된 레이블이 표시될 수 있으므로 쓰기 전 실제 구조를 확인해야 한다.

DUID는 OpenBSD가 디스크를 식별하기 위해 사용하는 고유 값이다. /etc/fstab과 부트 설정에서 0123456789abcdef.a 같은 형태로 DUID와 파티션 문자를 지정할 수 있다. 장치 번호보다 하드웨어 검색 순서 변화에 덜 의존한다.

disklabel -E는 대화형 편집기를 열어 파티션을 추가·삭제하고 크기와 마운트 지점을 계획할 수 있게 한다. 레이블 변경은 기존 파일 시스템의 데이터를 자동으로 이동하지 않으므로, 사용 중인 파티션의 시작 위치를 바꾸면 데이터에 접근할 수 없게 될 수 있다.

소프트웨어 RAID

OpenBSD의 소프트웨어 RAID는 softraid 커널 하위 시스템이 제공한다. 여러 디스크레이블 파티션을 하나의 논리 디스크로 결합하며, 생성된 볼륨은 다시 sd 장치로 나타난다.[92]

RAID 구성에 사용할 각 물리 디스크 영역은 디스크레이블에서 파일 시스템 종류를 RAID로 지정한다. 이 파티션들은 bioctl의 chunk로 전달되고 softraid0 컨트롤러가 논리 볼륨을 생성한다.

RAID 0은 데이터를 여러 장치에 분산하여 용량과 순차 처리량을 결합하지만 중복성을 제공하지 않는다. 구성 장치 하나가 손상되면 전체 볼륨의 데이터가 손상될 수 있다.

RAID 1은 같은 데이터를 둘 이상의 장치에 복제한다. 하나의 구성 장치가 고장 나도 남은 복사본으로 동작할 수 있으며, 교체 장치를 추가해 재구축할 수 있다.

RAID 1C는 데이터 복제와 함께 각 복사본의 무결성을 확인하기 위한 체크섬을 사용한다. 읽은 데이터의 체크섬이 맞지 않으면 정상 복사본을 이용해 잘못된 데이터를 복구할 수 있어, 단순한 장치 장애뿐 아니라 일부 비정상 데이터 변경을 탐지하는 데 사용된다.

CONCAT은 여러 장치의 공간을 순서대로 이어 하나의 큰 볼륨으로 만든다. RAID 0처럼 스트라이핑하지 않으며 중복성도 제공하지 않는다.

bioctl은 볼륨 생성과 상태 조회, 장치 오프라인 처리, 재구축과 암호화 볼륨 관리를 수행한다. RAID 0과 RAID 1은 최소 두 개의 chunk가 필요하고, CRYPTO는 정확히 하나의 chunk를 사용한다.[93]

생성된 softraid 볼륨은 일반 디스크와 동일하게 디스크레이블을 작성하고 FFS2 등의 파일 시스템을 만들 수 있다. 즉 RAID 계층과 파일 시스템 계층이 분리되어 있으며, FFS는 아래쪽 저장 장치가 물리 디스크인지 RAID 논리 볼륨인지 직접 구분할 필요가 없다.

RAID 1 또는 RAID 1C의 구성 장치가 실패하면 볼륨은 성능이나 중복성이 줄어든 degraded 상태로 동작할 수 있다. 관리자는 bioctl로 실패 장치를 오프라인 처리하고 새 RAID 파티션을 지정해 재구축한다.

소프트웨어 RAID는 백업을 대체하지 않는다. 파일 삭제, 파일 시스템 손상, 잘못된 관리 명령과 여러 장치에 동시에 영향을 주는 장애는 복제된 모든 구성 요소에 반영될 수 있다.

암호화된 저장 장치

OpenBSD의 전체 디스크 암호화는 softraid의 CRYPTO discipline으로 구성한다. 하나의 물리 디스크 파티션을 암호화된 논리 디스크로 변환하고, 그 위에 일반 디스크레이블과 파일 시스템을 만든다.

CRYPTO 볼륨을 만들 때 bioctl -c C와 암호화할 RAID 파티션을 지정한다. 생성된 볼륨은 새로운 sd 장치로 나타나며, 운영체제의 상위 저장 계층은 이를 일반적인 블록 장치처럼 사용한다.[94]

암호문과 암호화 메타데이터는 원래 물리 디스크에 저장되고, 올바른 키가 제공되면 커널이 읽기와 쓰기 과정에서 데이터를 투명하게 복호화·암호화한다. 파일 시스템에는 해독된 논리 블록만 보인다.

키는 사용자가 입력한 암호문에서 키 유도 함수로 만들거나 별도의 keydisk에 저장할 수 있다. 암호문 기반 구성에서는 반복 횟수를 시스템 성능에 맞게 조정하여 무차별 대입 비용을 높인다.

keydisk 방식은 별도의 USB 메모리 같은 장치에 키 자료를 저장한다. 암호화된 본체 디스크와 키 장치를 분리하여 보관할 수 있지만, 두 장치를 함께 분실하면 자동으로 보호 수준이 높아지는 것은 아니므로 물리적 관리가 필요하다.

부트 로더가 지원하는 플랫폼에서는 암호화된 softraid 볼륨 안의 루트 파일 시스템에서 OpenBSD를 부팅할 수 있다. 부팅 초기 단계에서 암호 또는 keydisk를 이용해 볼륨을 해제한 뒤 커널과 파일 시스템에 접근한다.

bioctl -P는 기존 CRYPTO 볼륨의 암호문을 변경하는 데 사용한다. 암호문 변경은 저장된 모든 데이터를 다시 암호화하기보다 데이터 암호화 키를 보호하는 키 자료를 갱신하는 방식으로 처리될 수 있다.

암호화는 전원이 꺼진 디스크나 분리된 저장 장치의 데이터 노출을 줄인다. 시스템이 실행 중이고 볼륨이 해제된 상태에서는 커널과 권한 있는 프로세스가 평문 데이터에 접근할 수 있으므로 사용자 권한, 화면 잠금과 시스템 보안이 함께 필요하다.

디스크 암호화는 데이터의 기밀성을 제공하지만 파일 삭제, 장치 고장과 파일 시스템 손상을 복구하지 않는다. 암호화 키나 메타데이터를 잃으면 정상 디스크라도 데이터를 복구하기 어려우므로 별도의 안전한 백업이 필요하다.

이동식 저장 장치

USB 메모리, 외장 SSD, 메모리 카드와 광학 매체 같은 이동식 저장 장치는 연결된 버스와 장치 종류에 맞는 드라이버를 통해 인식된다. USB 대용량 저장 장치는 일반적으로 umass를 거쳐 SCSI 디스크인 sd 장치로 연결된다.[95]

장치를 연결하면 dmesg에서 장치 이름, 용량, 섹터 크기와 연결된 드라이버를 확인할 수 있다. 이미 다른 디스크가 존재하면 새 장치는 sd1, sd2처럼 다음 번호를 받을 수 있다.

이동식 장치가 OpenBSD 디스크레이블과 FFS를 사용한다면 일반 로컬 디스크와 같은 방식으로 마운트한다. 다른 운영체제와 데이터를 교환하기 위한 장치에는 FAT 계통 파일 시스템이 흔히 사용되며, mount_msdos로 마운트할 수 있다.[96]

FAT 파일 시스템은 UNIX의 사용자·그룹, set-user-ID, 심볼릭 링크와 파일별 권한을 그대로 저장하지 못한다. 마운트할 때 모든 파일에 적용할 사용자 ID, 그룹 ID와 권한 마스크를 지정하는 방식으로 접근 권한을 표현한다.

CD와 DVD의 ISO 9660 파일 시스템은 mount_cd9660으로 읽을 수 있다. 광학 매체는 일반적으로 읽기 전용으로 마운트되며 디스크 장치가 아니라 cd 계열 장치로 나타날 수 있다.

이동식 장치를 분리하기 전에는 해당 파일 시스템을 umount해야 한다. 쓰기 캐시에 남아 있는 데이터와 메타데이터를 디스크에 반영하지 않고 장치를 제거하면 파일 시스템이 손상될 수 있다.

마운트 지점 내부를 현재 작업 디렉터리로 사용하거나 파일을 열고 있는 프로세스가 있으면 마운트 해제가 실패할 수 있다. fstat과 같은 도구로 해당 장치를 사용하는 프로세스를 확인할 수 있다.

신뢰할 수 없는 이동식 장치는 nodev, nosuid, 필요에 따라 noexec 옵션으로 마운트할 수 있다. 이를 통해 장치 파일 해석, set-user-ID 실행과 직접적인 프로그램 실행을 제한한다.

이동식 장치의 장치 번호는 연결 순서에 따라 바뀔 수 있으므로, 자동 마운트나 영구 설정에는 실제 파일 시스템과 DUID를 확인해야 한다. 장치 이름만 보고 포맷이나 레이블 작업을 실행하지 않도록 주의해야 한다.

네트워크 파일 시스템

OpenBSD는 네트워크를 통해 원격 디렉터리를 로컬 파일 시스템 트리에 연결하는 NFS를 기본 시스템에서 지원한다. 클라이언트는 원격 서버가 내보낸 파일 시스템을 특정 로컬 디렉터리에 마운트하여 일반 파일처럼 접근할 수 있다.

NFS 서버는 /etc/exports에서 외부에 공개할 디렉터리, 허용할 클라이언트와 접근 옵션을 정의한다. mountd는 내보내기 정책을 처리하고, nfsd는 실제 NFS 파일 요청을 처리한다.[97]

클라이언트는 mount_nfs를 사용하여 서버:/경로를 로컬 마운트 지점에 연결한다. /etc/fstab에 항목을 추가하면 부팅 과정에서 자동으로 마운트할 수 있다.[98]

NFS에서 파일 소유권은 기본적으로 숫자형 사용자 ID와 그룹 ID를 기준으로 해석된다. 서버와 클라이언트의 계정 이름이 같더라도 숫자 ID가 다르면 다른 사용자로 취급될 수 있으므로 계정 체계를 맞춰야 한다.

서버는 root 사용자의 요청을 일반적으로 제한된 사용자로 변환하여 원격 root가 서버 파일 시스템에서 같은 권한을 행사하지 못하도록 할 수 있다. 내보내기 옵션에 따라 읽기 전용, 허용 네트워크와 사용자 매핑을 설정한다.

NFS는 로컬 파일 시스템보다 네트워크 지연과 서버 장애의 영향을 받는다. hard·soft 마운트, 재시도, 시간 제한과 인터럽트 가능 여부에 따라 응용 프로그램이 장애 상황에서 보이는 동작이 달라질 수 있다.

NFS 자체의 전통적인 신뢰 모델은 클라이언트 주소와 사용자 ID에 크게 의존한다. 신뢰되지 않는 네트워크를 통과해야 한다면 IPsec, WireGuard와 같은 보호된 네트워크 계층을 결합하거나 접근 범위를 별도 망으로 제한할 수 있다.

SSHFS, SMB와 다른 네트워크 파일 시스템은 기본 시스템이 아닌 포트·패키지를 통해 사용할 수 있다. 이 경우 외부 프로그램의 구현과 보안 특성은 OpenBSD 기본 NFS 구성과 별도로 평가해야 한다.

파일 권한과 플래그

OpenBSD의 파일 접근 제어는 전통적인 UNIX 사용자·그룹·기타 권한, 파일 소유권, 특수 실행 비트와 파일 플래그를 중심으로 구성된다. 커널은 프로세스의 자격 증명과 파일 메타데이터를 비교하여 작업을 허용할지 결정한다.

각 파일에는 소유 사용자와 소유 그룹이 있다. 권한 비트는 소유자, 그룹 구성원과 그 밖의 사용자에 대해 읽기, 쓰기와 실행을 각각 지정한다.

일반 파일의 읽기 권한은 내용을 읽는 권한이고, 쓰기 권한은 내용을 변경하는 권한이다. 실행 권한은 파일을 프로그램이나 스크립트로 실행할 수 있게 한다.

디렉터리에서는 권한의 의미가 다르다. 읽기는 항목 이름 목록을 조회할 수 있게 하고, 쓰기는 항목 생성과 삭제를 허용하며, 실행은 경로를 통과하고 내부 객체에 접근할 수 있게 한다.

set-user-ID와 set-group-ID 비트가 설정된 실행 파일은 실행한 사용자가 아니라 파일 소유자 또는 그룹의 유효 권한으로 동작할 수 있다. 높은 권한의 프로그램에서 취약점이 발생하면 영향이 커질 수 있어 기본 시스템은 이러한 프로그램 수와 권한 유지 시간을 줄이는 방향을 따른다.

디렉터리의 sticky 비트는 여러 사용자가 쓰기 가능한 디렉터리에서도 각 사용자가 자신이 소유한 파일만 삭제하거나 이름을 변경하도록 제한한다. /tmp와 같은 공유 임시 디렉터리에 사용된다.

umask는 새 파일과 디렉터리를 만들 때 제거할 기본 권한을 지정한다. 프로그램이 요청한 모드에서 umask에 지정된 비트를 제외하여 지나치게 넓은 접근 권한으로 파일이 생성되는 것을 막는다.

chmod는 권한 비트를 변경하고, chownchgrp는 소유 사용자와 그룹을 바꾼다. 파일 시스템과 현재 사용자의 권한에 따라 이러한 변경 자체가 제한된다.

파일 플래그는 일반 권한 비트와 별도의 보호 속성이다. uchg는 사용자 변경 불가, uappnd는 사용자 추가 전용 상태를 지정하며, 시스템 플래그인 schgsappnd는 더 강한 보호에 사용된다.[99]

immutable 플래그가 설정된 파일은 내용 변경, 삭제와 이름 변경이 제한된다. append-only 플래그는 기존 데이터를 덮어쓰지 않고 끝에 추가하는 작업만 허용한다. 로그와 중요 시스템 파일 보호에 활용할 수 있다.

시스템 플래그를 제거할 수 있는 범위는 커널의 securelevel에 따라 달라진다. 높은 보안 수준에서는 root도 실행 중인 시스템에서 schg 같은 플래그를 해제하지 못할 수 있다.

마운트 옵션도 파일 권한의 해석에 영향을 준다. nosuid는 set-user-ID와 set-group-ID 비트의 효과를 막고, nodev는 해당 파일 시스템의 장치 특수 파일을 사용하지 못하게 하며, noexec는 일반 실행 파일의 직접 실행을 제한한다.

저장 장치 관리 도구

OpenBSD는 디스크 인식, 파티션 구성, 파일 시스템 생성, 검사, 마운트, RAID와 암호화 관리를 위한 도구를 기본 시스템에 포함한다. 각 도구는 저장 장치 계층의 서로 다른 부분을 담당한다.

dmesg는 커널이 인식한 저장 장치, 연결된 드라이버, 용량과 오류 메시지를 확인하는 데 사용한다. 실제 작업을 시작하기 전에 대상 장치 이름을 확인하는 첫 단계가 된다.

sysctl hw.disknames는 현재 인식된 디스크 이름과 DUID를 표시한다. 장치 번호와 고유 식별자를 함께 확인하여 /etc/fstab이나 관리 명령에 사용할 수 있다.

fdisk는 amd64 등에서 MBR과 GPT 파티션 테이블을 확인하고 편집한다. EFI 시스템 파티션, OpenBSD 영역과 다른 운영체제의 파티션을 디스크 바깥 단계에서 구성한다.[100]

disklabel은 OpenBSD 영역 안의 a부터 p까지 파티션을 관리한다. 파티션의 오프셋과 크기, FFS·swap·RAID 같은 유형을 설정한다.

newfs는 FFS 또는 FFS2 파일 시스템을 만들고, fsck_ffs는 일관성을 검사·복구한다. tunefs는 일부 파일 시스템 매개변수를 변경하고, growfs는 확장된 파티션에 맞춰 파일 시스템 크기를 늘린다.

mount와 파일 시스템별 mount_* 도구는 파일 시스템을 디렉터리 트리에 연결한다. umount는 사용을 마친 파일 시스템을 분리하고, mount -a/etc/fstab의 대상들을 일괄 처리한다.

df는 파일 시스템 공간과 inode 사용량을 보여주고, du는 디렉터리와 파일이 차지하는 공간을 계산한다. 두 명령의 수치는 열린 뒤 삭제된 파일, 희소 파일과 파일 시스템 메타데이터 때문에 다르게 나타날 수 있다.

bioctl은 하드웨어 RAID와 softraid 볼륨을 조회하고 관리한다. RAID·CRYPTO 볼륨 생성, 상태 확인, 구성 장치 교체, 재구축과 암호문 변경을 수행한다.[101]

swapctl은 스왑 장치와 파일을 활성화·비활성화하고 현재 스왑 사용량을 확인한다. 스왑 파티션은 디스크레이블에서 일반적으로 b 파티션과 swap 유형으로 구성한다.

vnconfig는 일반 파일을 가상 디스크 장치인 vnd에 연결한다. 디스크 이미지 안의 파티션과 파일 시스템을 마운트하거나 파일 기반 가상 저장 장치를 만드는 데 사용한다.[102]

dumprestore는 FFS 파일 시스템 백업에 사용되고, tar, paxcpio는 파일 단위 보관과 복사에 사용할 수 있다. RAID와 암호화가 장치 장애와 데이터 노출을 줄일 수는 있지만, 삭제·손상·관리 실수에 대비하려면 별도 백업이 필요하다.

저장 장치 명령 대부분은 즉시 디스크 메타데이터를 변경할 수 있다. 따라서 대상 장치의 dmesg, DUID, 기존 fdiskdisklabel 출력을 먼저 확인하고, 파티션 표나 파일 시스템을 다시 만드는 작업 전에는 필요한 데이터를 백업하는 것이 기본 흐름이다.

프로세스와 자원 관리

OpenBSD는 실행 중인 프로그램을 프로세스와 스레드 단위로 관리하고, CPU 시간, 가상 메모리, 열린 파일, 사용자 자격 증명과 여러 커널 자원을 각 실행 단위에 연결한다. 프로세스 생성과 프로그램 적재는 forkexec 계열 시스템 호출을 중심으로 이루어지며, 커널 스케줄러는 실행 가능한 스레드를 사용 가능한 CPU에 배치한다.

사용자와 그룹은 파일 접근과 시스템 작업의 권한 기준을 제공한다. OpenBSD는 여기에 로그인 클래스와 자원 제한을 결합하여 사용자·서비스 종류별로 프로세스 수, 메모리, 열린 파일, CPU 시간과 실행 환경을 제어한다.

시스템 데몬은 rc 체계와 rcctl을 통해 활성화하고 관리한다. 실행 상태와 자원 사용은 ps, top, systat, fstat, procmap, ktrace와 여러 진단 도구를 통해 확인할 수 있다.

OpenBSD의 자원 관리는 단순히 시스템 과부하를 방지하는 데 그치지 않는다. 서비스가 사용할 수 있는 권한과 자원의 범위를 미리 제한하면 프로그램 오류나 침해가 다른 사용자와 시스템 전체에 미치는 영향도 줄일 수 있다.

프로세스 생성과 실행

OpenBSD에서 프로세스는 독립된 가상 주소 공간, 파일 디스크립터 테이블, 사용자·그룹 자격 증명, 시그널 상태와 자원 제한을 가진 실행 환경이다. 하나의 프로세스 안에는 같은 주소 공간과 파일을 공유하는 여러 스레드가 존재할 수 있다.

새로운 프로세스는 주로 fork 계열 시스템 호출을 통해 생성된다. fork는 호출한 부모 프로세스의 실행 환경을 복제하여 자식 프로세스를 만들고, 부모에게는 자식의 프로세스 ID를, 자식에게는 0을 반환한다.[103]

프로세스의 가상 메모리는 생성 시 즉시 전체 복사되지 않는다. 부모와 자식은 처음에 같은 물리 메모리 페이지를 공유하고, 어느 한쪽이 페이지를 수정할 때 별도 복사본을 만드는 쓰기 시 복사 방식을 사용한다.

열린 파일 디스크립터도 부모와 자식이 같은 커널 파일 객체를 참조할 수 있다. 이 경우 파일 오프셋과 일부 상태가 공유되므로, 부모 또는 자식의 읽기·쓰기가 다른 쪽에서 보이는 파일 위치에 영향을 줄 수 있다.

새 프로세스를 만든 뒤 다른 프로그램을 실행할 때는 execve와 이에 기반한 함수들을 사용한다. execve는 현재 프로세스의 주소 공간을 실행 파일의 코드, 데이터, 스택과 공유 라이브러리 배치로 교체한다.[104]

exec가 성공해도 새로운 프로세스 ID가 만들어지는 것은 아니다. 기존 프로세스의 PID와 여러 커널 상태는 유지되며, 실행 중인 프로그램 이미지와 사용자 공간 문맥이 새 프로그램으로 바뀐다.

실행 파일은 일반적으로 ELF 형식을 사용한다. 커널은 실행 파일의 헤더, 프로그램 영역, 접근 권한과 인터프리터 정보를 검증하고 코드·데이터 영역을 가상 주소 공간에 배치한다. 동적 실행 파일은 런타임 링커가 필요한 공유 라이브러리를 추가로 적재한다.

set-user-ID 또는 set-group-ID 비트가 설정된 실행 파일은 실행 시 유효 사용자 ID나 그룹 ID를 파일 소유자에 맞게 변경할 수 있다. OpenBSD는 이러한 프로그램의 수를 줄이고, 실행 환경과 파일 디스크립터를 엄격하게 처리하는 방향을 따른다.

실행 시 FD_CLOEXEC이 설정된 파일 디스크립터는 자동으로 닫힌다. 서비스가 자식 프로그램을 실행할 때 불필요한 소켓, 로그 파일과 권한 있는 디스크립터가 새 프로그램으로 전달되는 것을 방지하는 데 사용된다.

프로세스가 종료되면 열린 파일과 메모리 자원이 해제되고 종료 상태가 부모에게 전달된다. 부모가 wait 계열 호출로 상태를 회수하기 전까지 종료된 프로세스는 최소한의 정보만 남은 좀비 상태로 유지될 수 있다.[105]

부모 프로세스가 먼저 종료되면 남은 자식은 시스템의 프로세스 계층에 다시 연결된다. 서비스 관리 프로그램은 자식 종료와 시그널을 감시하고 필요한 경우 프로세스를 다시 시작하거나 종료 상태를 로그에 남긴다.

스케줄링

OpenBSD의 스케줄러는 실행 가능한 스레드 가운데 다음에 CPU를 사용할 대상을 선택한다. 프로세스보다 실제 실행 흐름인 스레드가 스케줄링 단위이며, 같은 프로세스의 여러 스레드도 각각 독립적으로 실행 대기 상태를 가질 수 있다.

실행 가능한 스레드는 스케줄러의 실행 대기열에 들어간다. 현재 CPU에서 실행 중인 스레드가 시간 할당량을 소진하거나, 입출력을 기다리며 잠들거나, 더 높은 우선순위의 작업이 실행 가능해지면 문맥 전환이 일어날 수 있다.

문맥 전환 과정에서는 현재 스레드의 레지스터, 스택과 프로세서 상태를 저장하고 다음 스레드의 상태를 복원한다. 서로 다른 프로세스 사이의 전환에서는 가상 주소 공간과 관련된 페이지 테이블 상태도 변경될 수 있다.

스레드의 우선순위는 실행 특성과 대기 상태에 따라 동적으로 변할 수 있다. 대화형 프로그램처럼 짧게 실행한 뒤 자주 입출력을 기다리는 작업은 CPU를 장시간 연속 사용하는 계산 작업과 다른 스케줄링 특성을 보인다.

사용자는 nice 값을 통해 일반 프로세스의 CPU 스케줄링 우선순위에 영향을 줄 수 있다. 높은 nice 값은 다른 작업에 CPU를 양보하는 성향을 높이며, 우선순위를 더 유리하게 변경하는 작업에는 적절한 권한이 필요하다.[106]

실행 중인 프로세스의 nice 값은 renice로 조정할 수 있다. 사용자, 프로세스 ID 또는 프로세스 그룹을 대상으로 변경할 수 있지만 다른 사용자의 프로세스나 더 높은 우선순위를 설정하는 작업은 제한된다.[107]

스레드가 디스크, 네트워크, 잠금이나 타이머를 기다리면 수면 상태에 들어간다. 기다리던 조건이 충족되면 커널은 해당 스레드를 깨워 다시 실행 대기열에 넣는다.

멀티프로세서 시스템에서는 여러 CPU가 동시에 서로 다른 스레드를 실행한다. 스케줄러는 CPU별 실행 대기열과 부하를 고려해 작업을 배치하며, 필요하면 스레드를 다른 CPU로 이동시킬 수 있다.

커널의 일부 작업은 일반 사용자 스레드가 아니라 커널 스레드로 실행된다. 지연 가능한 장치 작업, 메모리 회수와 시스템 내부 유지 작업이 이러한 실행 문맥을 사용할 수 있다.

스케줄링 상태는 ps의 상태 필드, top, systat과 추적 도구로 관찰할 수 있다. 실행 대기 시간이 길거나 특정 프로세스가 CPU를 지속적으로 사용하는 경우 우선순위, 잠금 대기와 전체 시스템 부하를 함께 확인해야 한다.

메모리 관리

각 OpenBSD 프로세스는 독립된 가상 주소 공간을 가진다. 주소 공간에는 실행 코드, 초기화된 데이터, 힙, 스택, 공유 라이브러리와 mmap으로 생성된 영역이 배치된다.

사용자 프로세스가 보는 가상 주소는 커널의 UVM 하위 시스템과 아키텍처별 페이지 테이블을 통해 실제 물리 메모리 페이지로 변환된다. 서로 다른 프로세스가 같은 가상 주소를 사용해도 서로 다른 물리 페이지를 참조할 수 있다.

프로세스가 아직 물리 메모리가 연결되지 않은 유효 주소를 접근하면 페이지 폴트가 발생한다. 커널은 매핑 정보를 확인한 뒤 새 페이지를 할당하거나 파일·스왑에서 필요한 데이터를 읽는다.

힙 메모리는 C 라이브러리의 malloc 계열 함수나 mmap을 통해 확보할 수 있다. 사용자 공간 메모리 할당기는 커널에서 받은 가상 메모리 영역을 작은 객체 단위로 나누어 프로그램에 제공한다.

스택은 함수 호출, 지역 변수와 저장된 실행 문맥에 사용된다. 각 스레드는 독립된 사용자 스택을 가지며, 스택 크기는 로그인 클래스와 setrlimit으로 제한될 수 있다.

공유 라이브러리와 파일은 여러 프로세스의 주소 공간에 동시에 매핑될 수 있다. 읽기 전용 코드 페이지는 물리 메모리에서 공유하면서 각 프로세스가 서로 다른 가상 주소에 배치할 수 있다.

메모리가 부족하면 커널은 사용 빈도가 낮은 캐시와 페이지를 회수한다. 필요한 경우 익명 메모리 페이지를 스왑 장치로 내보내고, 다시 접근할 때 디스크에서 읽어온다.

프로세스가 사용할 수 있는 데이터 영역, 스택과 주소 공간 크기는 자원 제한의 영향을 받는다. 제한을 초과한 메모리 할당이나 스택 확장은 실패하거나 시그널로 이어질 수 있다.

ulimit 또는 로그인 클래스 설정은 프로세스가 사용할 수 있는 메모리 범위를 조정한다. 실제 사용 가능한 메모리는 해당 제한 외에도 물리 메모리, 스왑, 주소 공간 구조와 커널 정책의 영향을 받는다.

프로세스의 가상 메모리 배치는 procmap으로 확인할 수 있다. 코드, 데이터, 힙, 스택과 공유 라이브러리 영역의 주소, 크기와 접근 권한을 조사하는 데 사용된다.[108]

사용자와 그룹

OpenBSD의 사용자 계정은 프로세스와 파일의 소유권, 로그인 인증과 자원 정책을 구분하는 기본 단위다. 각 사용자는 이름과 숫자형 사용자 ID, 기본 그룹, 홈 디렉터리, 로그인 셸과 로그인 클래스를 가진다.

일반 사용자 정보는 /etc/passwd에서 확인할 수 있으며, 암호 해시와 더 민감한 계정 정보는 /etc/master.passwd에 저장된다. 후자는 일반 사용자가 읽을 수 없도록 보호된다.

pwd_mkdb는 master password 파일을 바탕으로 시스템이 빠르게 조회할 수 있는 계정 데이터베이스를 생성한다. 계정 파일을 직접 수정하기보다 vipw, chpass와 사용자 관리 도구를 사용하는 것이 일반적이다.

새 사용자 생성에는 useradd, 기존 계정 수정에는 usermod, 삭제에는 userdel을 사용한다. 이 도구들은 사용자 ID, 그룹, 홈 디렉터리, 셸과 로그인 클래스를 일관되게 관리한다.[109]

그룹은 여러 사용자에게 공통된 파일 접근 권한과 관리 권한을 부여하는 단위다. 그룹 정보는 /etc/group에 기록되고 각 그룹에는 이름, 숫자형 그룹 ID와 구성원 목록이 연결된다.

사용자는 하나의 기본 그룹과 여러 보조 그룹에 속할 수 있다. 프로세스는 로그인할 때 사용자의 사용자 ID, 기본 그룹과 보조 그룹 목록을 자격 증명으로 받는다.

파일 접근 시 커널은 프로세스의 유효 사용자 ID와 그룹 목록을 파일의 소유자·그룹, 권한 비트와 비교한다. root는 넓은 권한을 갖지만 securelevel, 파일 플래그와 프로세스별 보안 제한에 의해 일부 작업이 제한될 수 있다.

시스템 데몬에는 _sshd, _ntp, _smtp처럼 전용 사용자가 할당될 수 있다. 이러한 계정은 대화형 로그인보다 서비스의 파일 소유권과 권한 분리를 위해 사용된다.

wheel 그룹은 전통적으로 관리 권한과 관련된 특별한 그룹이다. su를 통해 root로 전환할 수 있는 사용자를 제한하거나 doas.conf 정책의 기준으로 사용할 수 있다.

사용자의 현재 ID와 그룹은 id로 확인한다. OpenBSD의 id -c는 사용자의 로그인 클래스도 표시할 수 있다.[110]

로그인 클래스

로그인 클래스는 개별 사용자마다 같은 설정을 반복하지 않고, 비슷한 역할의 사용자와 서비스에 공통 실행 환경과 자원 정책을 적용하는 OpenBSD의 기능이다.

사용자 계정에는 default, staff, daemon과 같은 로그인 클래스 이름을 지정할 수 있다. 로그인 프로그램과 서비스 관리 체계는 해당 클래스의 설정을 읽어 세션의 자원 제한과 환경을 구성한다.

기본 로그인 클래스 데이터베이스는 /etc/login.conf에 저장된다. OpenBSD 7.1부터는 /etc/login.conf.d 아래에 클래스별 데이터베이스를 추가할 수 있어 패키지와 로컬 서비스가 기본 파일을 직접 수정하지 않고 별도 클래스를 제공할 수 있다.[111]

로그인 클래스에는 프로세스 수, 열린 파일 수, 데이터·스택·메모리 크기, CPU 시간과 코어 덤프 크기의 기본값과 최대값을 지정할 수 있다. 로그인 세션은 기본값 범위에서 자신의 제한을 낮추거나, 허용된 경우 최대값까지 높일 수 있다.

datasize, stacksize, memoryuse, openfiles, maxproc, coredumpsizecputime 등이 대표적인 자원 관련 capability다. 각 항목은 -cur-max 형태로 현재 제한과 최대 제한을 구분할 수 있다.

로그인 클래스는 단순한 자원 제한 외에도 umask, 프로세스 우선순위, 환경 변수, 경로, 언어 설정, 세션 시간과 로그인 허용 조건을 지정할 수 있다.

staff 클래스는 일반 사용자보다 높은 자원 한도를 제공하는 관리용 사용자에 활용될 수 있다. daemon 클래스는 서비스 프로세스가 로그인 사용자와 다른 제한을 갖도록 구성하는 데 사용된다.

OpenBSD의 rcctl은 데몬별 로그인 클래스를 설정할 수 있다. 서비스 시작 시 daemon 클래스나 전용 클래스를 적용하여 메모리, 파일 디스크립터와 프로세스 수 제한을 서비스 특성에 맞게 지정할 수 있다.[112]

로그인 클래스 설정은 텍스트 데이터베이스 형식을 사용한다. 변경 뒤에는 cap_mkdb로 데이터베이스를 갱신할 수 있으며, 문법 오류와 상속 관계를 확인해야 한다.[113]

클래스 항목은 다른 클래스를 상속할 수 있다. 공통 기본값을 하나의 클래스에 정의하고 서버, 개발자, 일반 사용자와 특정 데몬용 클래스에서 필요한 부분만 덮어쓸 수 있다.

로그인 클래스는 이미 실행 중인 모든 프로세스의 제한을 자동으로 변경하지 않는다. 새 로그인 세션이나 서비스 시작 시 정책이 적용되므로 변경 내용을 반영하려면 해당 세션이나 데몬을 다시 시작해야 할 수 있다.

자원 제한

OpenBSD는 프로세스가 사용할 수 있는 CPU 시간, 메모리, 파일 크기, 열린 파일, 프로세스 수와 코어 덤프 크기 등에 연성 제한과 경성 제한을 적용한다.

연성 제한은 현재 실행에 적용되는 값이다. 프로세스는 자신의 연성 제한을 낮출 수 있고, 경성 제한을 넘지 않는 범위에서는 다시 높일 수 있다.

경성 제한은 프로세스가 일반 권한으로 설정할 수 있는 최대값이다. 경성 제한을 높이는 작업은 권한과 시스템 정책에 따라 제한된다.

프로그램은 getrlimit으로 현재 값을 읽고 setrlimit으로 변경한다. 제한은 대체로 자식 프로세스에 상속되며 exec 이후에도 유지되므로, 로그인 세션이나 서비스 시작 단계에서 설정하면 이후 실행되는 프로그램 전체에 적용된다.[114]

RLIMIT_CPU는 프로세스가 소비할 수 있는 CPU 시간을 제한한다. 연성 제한에 도달하면 시그널이 전달되고, 계속 실행하여 경성 제한을 넘으면 종료될 수 있다.

RLIMIT_FSIZE는 프로세스가 만들 수 있는 파일의 최대 크기를 제한한다. 제한을 넘는 쓰기는 실패하거나 SIGXFSZ 시그널을 발생시킬 수 있다.

RLIMIT_DATA, RLIMIT_STACKRLIMIT_AS 계열 제한은 데이터 영역, 스택과 전체 주소 공간에 영향을 준다. 실제 할당 가능 여부는 물리 메모리와 가상 메모리 상태에도 좌우된다.

RLIMIT_NOFILE은 하나의 프로세스가 열 수 있는 파일 디스크립터 수를 제한한다. 많은 동시 연결을 처리하는 네트워크 서비스에서는 이 값과 시스템 전체 파일 테이블 용량을 함께 고려해야 한다.

RLIMIT_NPROC는 한 사용자가 생성할 수 있는 프로세스와 스레드 수를 제한한다. 잘못된 프로그램이 반복적으로 자식 프로세스를 만드는 상황이 시스템 전체의 프로세스 공간을 소진하는 것을 줄인다.

RLIMIT_CORE는 오류 발생 시 생성할 수 있는 코어 덤프의 크기를 제한한다. 민감한 정보가 포함될 수 있는 서비스는 코어 덤프를 비활성화하거나 저장 위치와 권한을 제한할 수 있다.

셸에서는 ulimit을 통해 현재 세션과 이후 실행할 자식 프로세스의 제한을 확인하고 변경할 수 있다. ksh의 옵션과 단위는 셸 매뉴얼에 정의된다.[115]

시스템 전체 한도는 프로세스별 제한과 별개로 존재한다. 커널의 최대 프로세스 수, 열린 파일 수와 여러 네트워크·메모리 자원은 sysctl 설정과 커널 자료구조의 영향을 받는다.

자원 제한은 성능 조정뿐 아니라 격리 수단이다. 특정 사용자나 데몬이 비정상적으로 많은 프로세스, 메모리와 파일 디스크립터를 점유하더라도 다른 서비스가 사용할 자원을 완전히 소진하지 않도록 한다.

데몬과 서비스 관리

OpenBSD의 시스템 서비스는 rc 부팅 체계와 rc.d 스크립트를 통해 관리된다. 기본 시스템 데몬과 패키지로 설치한 서비스 모두 공통된 rcctl 명령으로 활성화·비활성화하고 시작 상태를 제어할 수 있다.

부팅 과정에서는 /etc/rc가 시스템 초기화 작업을 수행하고 활성화된 데몬을 시작한다. 관리자는 기본 스크립트를 직접 수정하기보다 /etc/rc.conf.local에 로컬 설정을 기록한다.

기본 시스템의 서비스 스크립트는 /etc/rc.d에 위치한다. 패키지 서비스의 rc 스크립트도 같은 관리 인터페이스를 사용하지만, 프로그램과 관련 파일은 일반적으로 /usr/local 아래에 설치된다.

서비스를 다음 부팅부터 활성화하려면 rcctl enable, 비활성화하려면 rcctl disable을 사용한다. 이 명령은 /etc/rc.conf.local에 필요한 설정을 기록한다.[116]

rcctl start, stop, restart, reloadcheck는 실행 중인 서비스의 상태를 제어한다. 모든 데몬이 설정 재적재를 지원하는 것은 아니며, 지원되는 동작은 해당 rc 스크립트와 데몬의 기능에 따라 달라진다.

rcctl set으로 데몬의 실행 플래그, 사용자와 로그인 클래스를 설정할 수 있다. 많은 연결이나 메모리를 사용하는 서비스에는 전용 로그인 클래스를 지정해 기본 daemon 클래스와 다른 자원 제한을 적용할 수 있다.

rcctl getgetdef는 현재 설정과 기본값을 비교하는 데 사용한다. 서비스가 어떤 옵션과 사용자, 클래스로 시작되는지 확인할 수 있다.

rcctl ls는 활성화된 데몬, 실행 중인 데몬과 실패한 데몬을 분류하여 표시한다. ls rogue는 실행 중이지만 부팅 설정에는 활성화되지 않은 서비스를 찾는 데 사용할 수 있다. 이 기능은 OpenBSD 7.1 계열에서 추가되었다.[117]

각 rc 스크립트는 프로그램 시작, 종료, 프로세스 확인과 설정 검사 방법을 정의한다. 공통 함수는 rc.subr에서 제공되어 서비스마다 서로 다른 임시 관리 스크립트를 작성하는 상황을 줄인다.[118]

데몬은 일반적으로 포그라운드 초기화 뒤 자체적으로 백그라운드화하거나 rc 체계가 정한 방식으로 실행된다. 일부 현대 데몬은 직접 daemonize하지 않고 감시 프로세스 또는 서비스 관리 환경에서 포그라운드로 실행할 수 있다.

서비스가 시작되지 않으면 먼저 rcctl check, 시스템 로그와 데몬의 설정 검사 옵션을 확인한다. 포트 충돌, 파일 권한, 로그인 클래스 제한, 잘못된 설정 파일과 필요한 인터페이스가 준비되지 않은 상태가 원인이 될 수 있다.

OpenBSD의 rc 체계는 복잡한 서비스 의존성 그래프보다 예측 가능한 부팅 순서와 명시적인 설정을 지향한다. 네트워크, 파일 시스템과 기본 인프라가 준비된 뒤 서비스가 시작되며, 특수한 순서가 필요한 경우 rc 스크립트와 부팅 단계에 반영한다.

프로세스 관찰과 진단

OpenBSD는 현재 프로세스 목록, CPU·메모리 사용량, 열린 파일, 가상 주소 공간, 시스템 호출과 커널 상태를 확인하는 도구를 기본 시스템에 포함한다.

ps는 프로세스 ID, 부모 ID, 사용자, 상태, 터미널, CPU 시간과 명령행을 표시한다. 출력 필드를 직접 선택할 수 있어 프로세스 계층, 세션, 스레드와 보안 상태를 조사하는 데 사용한다.[119]

프로세스 상태에는 실행 중, 수면, 정지, 유휴와 좀비 등이 표시된다. 일부 상태 플래그는 프로세스가 chroot 환경에 있거나 pledge 같은 제한을 사용하는지도 나타낼 수 있다.

top은 실행 중인 프로세스와 시스템 전체 CPU·메모리 상태를 주기적으로 갱신하여 보여준다. CPU 사용량, 프로세스 크기, 실행 시간과 우선순위를 기준으로 정렬할 수 있다.[120]

systat은 프로세스뿐 아니라 CPU, 가상 메모리, 디스크 입출력, 네트워크 인터페이스, PF 상태와 소켓 사용량을 대화형 화면으로 표시한다. 전체 시스템 병목을 특정 자원과 연결해 확인하는 데 유용하다.[121]

pgrep은 이름과 속성으로 프로세스를 검색하고, pkill은 일치하는 프로세스에 시그널을 보낸다. 단순한 명령 이름 외에도 사용자, 그룹, 세션과 부모 프로세스를 기준으로 선택할 수 있다.

kill은 프로세스에 시그널을 전달한다. 일반적인 종료 요청에는 SIGTERM을 사용하고, 프로세스가 정리 작업을 수행할 수 없는 경우에만 SIGKILL을 사용한다. SIGKILL은 프로그램이 처리하거나 무시할 수 없다.

fstat은 프로세스가 열고 있는 파일, 소켓, 파이프와 장치의 정보를 보여준다. 마운트 해제를 방해하는 프로세스, 특정 네트워크 포트를 사용하는 서비스와 삭제된 파일을 계속 열고 있는 프로세스를 찾을 수 있다.[122]

procmap은 프로세스의 가상 메모리 매핑을 표시한다. 실행 파일, 공유 라이브러리, 힙, 스택과 익명 매핑의 주소 범위와 접근 권한을 확인할 수 있다.

pstat은 열린 파일 테이블, vnode, 터미널과 스왑 같은 커널 자원 상태를 표시한다. 프로세스별 도구보다 시스템 전체 커널 자료구조 사용량을 진단하는 데 가깝다.[123]

vmstat은 프로세스 실행 대기, 메모리 페이지, 페이지 폴트, 인터럽트, 시스템 호출과 CPU 시간 통계를 표시한다. 일정 간격으로 출력하면 시스템이 CPU, 메모리 또는 입출력 가운데 어디에서 압력을 받고 있는지 파악할 수 있다.[124]

ktrace는 프로세스의 시스템 호출, 시그널, 입출력과 이름 조회 같은 실행 사건을 기록한다. 생성된 추적 파일은 kdump로 읽으며, 프로그램이 어떤 파일을 찾고 어떤 시스템 호출에서 실패했는지 분석할 수 있다.[125][126]

truss는 대상 프로그램의 시스템 호출을 실시간으로 표시하는 데 사용할 수 있다. 전체 추적 파일이 필요하지 않은 간단한 오류 경로 분석에 적합하다.

btrace는 커널의 동적 추적 기능을 이용해 시스템 호출, 스케줄러와 커널 함수의 실행을 관찰한다. OpenBSD 7.1에는 실행 대기열 지연과 커널 스택을 조사하기 위한 공통 BPFtrace 스크립트가 추가되었다.[127]

프로세스가 비정상 종료하며 코어 덤프를 생성하면 gdb와 같은 디버거로 당시의 스택, 레지스터와 메모리 상태를 조사할 수 있다. 코어 덤프 생성 여부와 최대 크기는 로그인 클래스와 자원 제한, 파일 권한의 영향을 받는다.

진단 과정에서는 한 도구의 수치만으로 원인을 단정하기보다 프로세스 상태, 열린 자원, 시스템 전체 부하와 로그를 함께 확인해야 한다. CPU 사용량이 낮더라도 디스크, 네트워크, 잠금이나 메모리 회수를 기다리는 프로세스는 긴 지연을 보일 수 있다.

기본 시스템과 명령줄 환경

OpenBSD의 기본 시스템은 커널과 시스템 라이브러리뿐 아니라 셸, 파일 관리 명령, 텍스트 처리 도구, 네트워크 프로그램, 컴파일러, 시스템 초기화 도구와 매뉴얼을 함께 포함한다. 시스템 설치와 관리, 소프트웨어 개발, 네트워크 진단과 기본 서버 운영에 필요한 주요 기능을 외부 패키지 없이 사용할 수 있도록 구성되어 있다.

기본 시스템의 프로그램은 주로 /bin, /sbin, /usr/bin/usr/sbin에 설치된다. 일반 사용자가 실행하는 기본 명령은 /bin/usr/bin, 시스템 부팅과 관리에 필요한 명령은 /sbin/usr/sbin에 배치되는 경향이 있다. 패키지로 추가한 프로그램은 주로 /usr/local 아래에 설치되어 기본 시스템과 구분된다.

OpenBSD의 명령줄 환경은 작은 프로그램을 파이프와 파일 리디렉션으로 조합하는 전통적인 UNIX 사용 방식을 따른다. 하나의 프로그램이 모든 관리 작업을 처리하기보다 파일 검색, 텍스트 변환, 프로세스 관리와 네트워크 진단을 담당하는 여러 도구를 조합한다.

각 명령과 설정 파일의 공식 설명은 매뉴얼 페이지로 제공된다. 명령의 이름을 알고 있으면 man, 관련 개념이나 설명으로 찾을 때는 apropos를 사용할 수 있다. 기본 시스템에 포함된 도구와 문서가 함께 개발되므로 명령 동작과 매뉴얼을 같은 릴리스에서 맞춰 관리할 수 있다.[128]

기본 셸

OpenBSD의 기본 명령 셸은 공개 도메인 KornShell에서 발전한 ksh다. 대화형 명령 실행과 셸 스크립트 작성을 모두 지원하며 명령 기록, 별칭, 함수, 작업 제어, 명령줄 편집과 변수 확장 기능을 제공한다.

OpenBSD의 ksh는 흔히 pdksh 계통으로 설명되지만, OpenBSD 소스 트리에서 장기간 독립적으로 수정되고 유지되어 왔다. 다른 운영체제에서는 이 구현의 이식판이 oksh 등의 이름으로 배포되기도 한다.

대화형 로그인 셸은 사용자 계정의 셸 필드에 지정된다. 사용 가능한 로그인 셸의 목록은 /etc/shells에 기록되며, chsh 또는 chpass를 통해 허용된 셸로 변경할 수 있다.

ksh는 POSIX 셸과 호환되는 기본 문법에 KornShell의 확장 기능을 더한다. 변수 대입, 조건문, 반복문, 함수, 산술 확장, 명령 치환과 파이프를 사용하여 시스템 관리 스크립트를 작성할 수 있다.

명령 기록은 이전에 실행한 명령을 다시 불러오거나 검색하는 데 사용된다. Emacs식 또는 vi식 명령줄 편집 모드를 선택할 수 있으며, 탭 완성과 별칭을 통해 반복적인 명령 입력을 줄일 수 있다.

셸은 명령을 자체 내장 명령으로 처리하거나 PATH에서 실행 파일을 찾아 새 프로세스로 실행한다. 파이프를 구성할 때는 여러 프로세스를 생성하고 각 프로세스의 표준 입력과 출력을 연결한다.

입출력 리디렉션을 사용하면 표준 입력, 표준 출력과 표준 오류를 파일이나 다른 파일 디스크립터에 연결할 수 있다. 이를 통해 명령 출력을 파일에 저장하거나 오류만 따로 기록하고, 여러 명령을 하나의 처리 흐름으로 결합한다.

작업 제어는 대화형 셸에서 프로세스 그룹을 포그라운드와 백그라운드로 전환하는 기능이다. jobs, fg, bg와 시그널 입력을 사용하여 여러 작업을 하나의 터미널에서 관리할 수 있다.

셸 시작 파일은 로그인 여부와 실행 방식에 따라 다르게 읽힌다. 시스템 전체 설정과 사용자 홈 디렉터리의 프로필 파일에서 환경 변수, 경로, umask, 별칭과 터미널 설정을 정의할 수 있다.

root 계정도 기본적으로 ksh를 사용할 수 있지만, 관리 스크립트는 가능한 한 특정 사용자의 대화형 설정에 의존하지 않도록 작성해야 한다. cron, rc와 다른 자동 실행 환경은 로그인 셸보다 제한된 환경 변수와 경로를 사용할 수 있다.[129]

기본 시스템에는 C 셸 계통인 csh도 포함된다. Bash, Zsh, Fish와 다른 셸은 패키지로 설치할 수 있지만, 기본 시스템의 관리 절차와 공식 예시는 일반적으로 OpenBSD ksh와 표준 셸 환경을 기준으로 한다.

시스템 명령어

OpenBSD의 기본 시스템에는 파일, 디렉터리, 프로세스, 사용자 환경과 장치를 관리하는 전통적인 UNIX 명령어가 포함된다. 이들은 특정 데스크톱 환경이나 원격 관리 플랫폼에 의존하지 않고 콘솔과 SSH 세션에서 동일하게 사용할 수 있다.

파일과 디렉터리 관리에는 ls, cp, mv, rm, mkdir, rmdir, ln, touchinstall 등이 사용된다. 파일의 종류와 속성은 file, stat, ls -l로 확인할 수 있다.

cp는 파일과 디렉터리를 복사하고, mv는 이름을 변경하거나 같은 파일 시스템 안에서 위치를 옮긴다. rm은 파일 이름과 파일 시스템 객체의 연결을 제거하지만 다른 하드 링크나 열린 파일 디스크립터가 남아 있으면 데이터가 즉시 사라지지 않을 수 있다.

하드 링크는 같은 파일 시스템의 inode를 여러 이름으로 참조하고, 심볼릭 링크는 다른 경로 문자열을 저장한다. ln은 두 종류의 링크를 만들며, 파일 시스템 경계와 디렉터리에 대한 규칙은 서로 다르다.

파일 내용을 확인하는 기본 도구에는 cat, head, tail, more, less, od, hexdumpstrings가 있다. 로그처럼 계속 증가하는 파일은 tail -f로 새 내용을 관찰할 수 있다.

파일 검색에는 find, 명령 검색에는 whichwhereis, 매뉴얼 설명 검색에는 apropos가 사용된다. locate는 미리 생성된 파일 이름 데이터베이스를 검색하므로 실제 파일 시스템 상태와 차이가 있을 수 있다.

파일 권한과 소유권은 chmod, chown, chgrpchflags로 관리한다. umask는 새 파일과 디렉터리에 적용할 기본 권한을 제한한다.

프로세스에는 ps, pgrep, pkill, kill, nice, renicetime을 사용할 수 있다. 실행 중인 프로그램을 종료할 때는 일반적으로 정리 기회를 주는 SIGTERM을 먼저 사용하고, 응답하지 않는 경우에만 SIGKILL을 고려한다.

디스크와 파일 시스템 상태는 df, du, mount, fstat, disklabelsysctl hw.disknames로 확인할 수 있다. 각 명령은 파일 시스템 공간, 파일별 사용량, 마운트 상태와 실제 장치 구성을 서로 다른 관점에서 보여준다.

사용자와 그룹 관련 명령에는 id, who, w, last, su, doas, passwd, chpass, useradd, usermodgroupadd 등이 있다. 일반 사용자용 명령과 관리자용 명령은 매뉴얼의 1절과 8절로 구분되는 경우가 많다.

시스템 상태와 하드웨어 정보는 uname, sysctl, dmesg, vmstat, iostat, systattop으로 조사한다. 하나의 명령 출력만으로 문제를 판단하기보다 CPU, 메모리, 장치와 프로세스 상태를 함께 확인해야 한다.

명령어의 옵션과 출력은 다른 UNIX 계열과 유사하지만 완전히 같지는 않다. GNU 도구에만 존재하는 긴 옵션이나 비표준 동작을 가정한 스크립트는 OpenBSD 기본 도구에서 작동하지 않을 수 있으므로 해당 명령의 OpenBSD 매뉴얼을 기준으로 해야 한다.

텍스트 처리 도구

OpenBSD는 설정 파일, 로그와 프로그램 출력을 처리하기 위한 여러 텍스트 도구를 기본 시스템에 포함한다. 이 도구들은 표준 입력을 읽고 표준 출력으로 결과를 보내므로 파이프로 쉽게 조합할 수 있다.

grep은 입력에서 정규 표현식과 일치하는 행을 찾는다. 파일 검색뿐 아니라 다른 명령의 출력에서 필요한 항목을 골라내는 데 사용되며, 기본 정규 표현식과 확장 정규 표현식을 지원한다.

sed는 입력 스트림에 편집 명령을 순서대로 적용한다. 문자열 치환, 행 선택, 삭제와 간단한 변환에 사용되며 원본 파일을 직접 열어 대화형으로 편집하기보다 자동화된 처리에 적합하다.

awk는 입력을 레코드와 필드로 나누고 패턴에 맞는 동작을 수행하는 프로그래밍 언어다. 열 선택, 집계, 조건 처리와 형식 변환을 하나의 프로그램으로 표현할 수 있다.[130]

cut은 구분 문자나 문자 위치를 기준으로 필드를 추출하고, paste는 여러 파일의 행을 옆으로 결합한다. join은 공통 필드를 기준으로 두 정렬된 입력을 결합한다.

sort는 행을 지정된 기준으로 정렬하고, uniq는 인접한 중복 행을 제거하거나 개수를 계산한다. 중복 전체를 찾으려면 입력을 먼저 정렬해야 하는 경우가 많다.

tr은 문자 집합을 치환하거나 삭제하고, col, expand, unexpandfmt는 공백, 탭과 문단 형식을 정리한다. fold는 긴 행을 지정한 폭으로 나눈다.

wc는 바이트, 문자, 단어와 행 수를 계산한다. 파이프의 마지막에서 필터링된 항목 수를 확인하거나 파일 규모를 간단하게 조사하는 데 사용한다.

xargs는 표준 입력에서 항목을 읽어 다른 명령의 인수 목록으로 변환한다. 명령줄 길이 제한을 고려하여 여러 번 나누어 실행할 수 있지만, 파일 이름에 공백과 줄바꿈이 포함될 수 있는 경우 입력 구분 방식을 주의해야 한다.

tee는 입력을 표준 출력으로 전달하면서 파일에도 기록한다. 파이프 처리 결과를 화면에서 보면서 동시에 로그로 남길 때 사용할 수 있다.

diff, sdiffcmp는 파일 사이의 차이를 비교한다. patch는 통합 차이 형식 등의 패치를 원본 파일에 적용하며 OpenBSD 소스 코드와 보안 수정 배포에도 사용된다.

pax, tar, cpio, gzipcompress는 파일 묶음과 압축을 처리한다. 패키지와 설치 파일의 내부 형식은 전용 도구로 관리되지만 일반적인 백업과 파일 전송에는 이러한 기본 프로그램을 사용할 수 있다.

m4는 매크로 처리 언어로 빌드 과정과 일부 설정 생성에 사용된다. make와 셸 스크립트, 텍스트 필터를 조합하면 별도의 대규모 자동화 환경 없이도 반복 작업을 구성할 수 있다.

이러한 도구들은 작은 역할에 집중한다. 복잡한 작업은 하나의 거대한 명령보다 여러 도구를 파이프, 임시 파일과 셸 제어문으로 조합하는 방식으로 표현된다.

시스템 관리 도구

OpenBSD는 설치된 시스템의 설정, 계정, 서비스, 패키지, 커널 상태와 업데이트를 관리하는 도구를 기본 사용자 공간에 포함한다.

rcctl은 시스템 데몬과 패키지 서비스를 활성화, 비활성화, 시작, 중지하고 실행 옵션을 설정한다. 변경 사항은 주로 /etc/rc.conf.local에 기록되며 기본 부팅 스크립트를 직접 수정할 필요를 줄인다.

sysctl은 커널이 공개하는 시스템 변수와 상태를 조회하고 일부 값을 변경한다. 하드웨어, 네트워크, 프로세스, 보안 수준과 커널 자원에 관한 항목이 계층적인 이름으로 제공된다.

지속적으로 적용해야 하는 커널 설정은 /etc/sysctl.conf에 기록할 수 있다. 모든 sysctl 항목이 실행 중 변경 가능한 것은 아니며, 플랫폼과 현재 보안 수준에 따라 제한될 수 있다.

계정 관리는 useradd, usermod, userdel, groupadd, groupmod, passwdchpass를 사용한다. 이 도구들은 /etc/master.passwd, /etc/group과 관련 데이터베이스를 일관된 방식으로 갱신한다.

doas는 허가된 사용자가 특정 명령을 다른 사용자 권한으로 실행하게 한다. 정책은 /etc/doas.conf에 정의되며 실행 기록은 기본적으로 보안 로그에 남는다.[131]

패키지는 pkg_add, pkg_delete, pkg_infopkg_check로 관리한다. 기본 시스템 파일 세트는 패키지 데이터베이스의 대상이 아니며 운영체제 설치·업그레이드 도구로 갱신한다.[132]

기본 시스템의 바이너리 패치는 syspatch로 적용할 수 있다. 새 정식 릴리스로 전환할 때는 sysupgrade, 설정 파일 병합에는 sysmerge가 사용된다.

config, disklabel, fdisk, bioctl, mount, fscknewfs는 커널·디스크·파일 시스템 관리에 사용된다. 저장 장치 구성 도구는 즉시 데이터 구조를 변경할 수 있으므로 대상 장치와 현재 레이아웃을 먼저 확인해야 한다.

네트워크 관리에는 ifconfig, route, netstat, arp, ndp, pfctl과 프로토콜별 관리 도구가 사용된다. 영구 설정은 /etc/hostname.if, /etc/pf.conf와 데몬별 설정 파일에 기록한다.

shutdown, reboot, haltpoweroff는 시스템 종료 상태를 제어한다. 정상 종료 과정은 서비스 중지, 파일 시스템 동기화와 마운트 해제를 수행하므로 전원을 직접 차단하는 방식보다 안전하다.

관리 도구는 기능을 변경하는 명령과 현재 상태만 조회하는 명령을 함께 제공하는 경우가 많다. 실제 변경 전에 문법 검사나 조회 옵션을 사용하고, 설정 파일과 실행 중인 상태가 일치하는지 확인하는 것이 일반적이다.

편집기

OpenBSD 기본 시스템에는 터미널에서 사용할 수 있는 텍스트 편집기가 포함된다. 설정 파일과 소스 코드를 수정할 때 외부 패키지나 그래픽 환경이 없어도 작업할 수 있다.

vi는 기본적인 화면 지향 텍스트 편집기다. OpenBSD의 vi는 전통적인 BSD nvi 계통이며 명령 모드와 입력 모드를 구분한다.

명령 모드에서는 커서 이동, 삭제, 복사, 붙여넣기, 검색과 저장 같은 편집 명령을 실행한다. 입력 모드에서는 실제 문자를 문서에 삽입한다. 모드가 분리되어 있어 처음 사용하는 사용자에게는 익숙하지 않을 수 있지만 터미널 환경에서 빠른 편집과 명령 조합이 가능하다.[133]

vi는 여러 파일, 정규 표현식 검색·치환, 마크, 버퍼, 실행 취소와 셸 명령 실행을 지원한다. 시스템 복구 환경이나 원격 접속에서도 사용할 수 있으므로 기본적인 조작법을 알아두는 것이 유용하다.

mg는 Emacs와 유사한 키 조작을 제공하는 작은 텍스트 편집기다. 전체 GNU Emacs 구현은 아니며 기본적인 파일 편집, 버퍼, 검색과 명령 실행에 집중한다.[134]

ed는 행 단위 편집기다. 화면 전체를 사용하는 인터페이스가 필요하지 않고 매우 제한된 터미널에서도 사용할 수 있다. 셸 스크립트나 자동화된 수정에 활용할 수도 있다.

사용할 기본 편집기는 EDITORVISUAL 환경 변수로 지정할 수 있다. crontab -e, vipw, 버전 관리 도구와 여러 관리 프로그램이 이 변수를 참조한다.

vipw는 일반 편집기를 직접 실행하는 것과 달리 사용자 계정 데이터베이스를 안전하게 잠그고 편집 결과를 검증한다. 형식과 데이터베이스 갱신이 중요한 파일은 가능한 한 전용 편집 도구를 사용하는 것이 좋다.

Vim, Neovim, GNU Emacs, Nano와 그래픽 편집기는 패키지로 설치할 수 있다. 다만 원격 복구와 최소 설치 환경에서는 기본 vi, mg 또는 ed만 사용할 수 있으므로 기본 시스템 도구와 외부 편집기를 구분해야 한다.

컴파일러와 개발 도구

OpenBSD는 기본 시스템과 응용 프로그램을 빌드하고 디버깅하기 위한 개발 도구를 설치 파일 세트로 제공한다. 설치할 때 compXX.tgz를 선택하면 컴파일러, 링커, 헤더 파일과 여러 개발 도구가 설치된다.

현대 OpenBSD의 기본 C·C++ 컴파일러 체계는 지원 아키텍처에 따라 LLVM의 Clang을 중심으로 구성된다. 일부 플랫폼은 아키텍처 지원 상황에 따라 GCC 계통 도구를 사용할 수 있다.

cc는 시스템의 기본 C 컴파일러를 가리키는 일반적인 명령 이름이다. C++에는 c++를 사용하며 실제 구현은 플랫폼과 릴리스에 따라 연결된다.

컴파일 과정은 전처리, 소스 코드 번역, 어셈블, 링크 단계로 이루어진다. 컴파일러 드라이버는 필요한 도구와 시스템 헤더, 시작 파일과 라이브러리를 호출하여 실행 파일이나 객체 파일을 만든다.

make는 Makefile에 기록된 대상, 의존 관계와 명령을 읽어 필요한 파일만 다시 빌드한다. OpenBSD 기본 시스템과 포트 컬렉션은 BSD make 문법과 확장 기능을 사용하므로 GNU make 전용 문법과는 차이가 있다.[135]

as, ld, ar, nm, objdump, readelf, sizestrip 등의 도구는 어셈블, 링크, 정적 라이브러리와 실행 파일 구조를 처리한다. 실제 제공 도구와 구현은 아키텍처에 따라 달라질 수 있다.

lexyacc는 각각 어휘 분석기와 구문 분석기 생성에 사용된다. OpenBSD의 yacc는 전통적인 Berkeley yacc 계통이며 C 프로그램의 파서 생성에 사용할 수 있다.

m4, make, 셸, awksed는 빌드 설정과 코드 생성에도 사용된다. OpenBSD의 기본 시스템 빌드는 별도의 외부 빌드 프레임워크보다 이러한 기본 UNIX 도구를 폭넓게 활용한다.

소스 코드 버전 관리는 기본적으로 CVS 도구와 프로젝트 저장소 구조를 이용해 왔다. OpenBSD 공식 소스 트리는 CVS를 기준으로 관리되며 사용자는 익명 CVS 또는 배포된 소스 아카이브를 받을 수 있다.

디버깅에는 gdb 또는 LLVM 디버거 계통 도구, 코어 덤프, ktrace, kdump, trussbtrace 등을 사용할 수 있다. 모든 도구가 같은 목적을 갖는 것은 아니며 소스 수준 디버깅, 시스템 호출 추적과 커널 이벤트 관찰을 구분한다.

시스템 헤더는 /usr/include, 기본 라이브러리는 /usr/lib에 위치한다. 패키지의 헤더와 라이브러리는 /usr/local/include/usr/local/lib에 설치되어 기본 시스템 개발 파일과 분리된다.

OpenBSD 시스템 자체를 소스에서 빌드할 때는 현재 설치된 바이너리와 소스 트리의 버전을 맞춰야 한다. 정식 릴리스 사이를 소스 컴파일만으로 건너뛰는 방식은 지원되는 일반 업그레이드 절차가 아니며, 먼저 가장 가까운 바이너리 릴리스나 스냅샷으로 갱신해야 한다.[136]

기본 네트워크 프로그램

OpenBSD의 기본 시스템에는 원격 접속, 파일 전송, 이름 조회, 연결 시험과 네트워크 진단을 위한 프로그램이 포함된다. 많은 도구는 OpenBSD 프로젝트가 직접 유지하거나 기본 시스템에 맞게 감사한 구현이다.

ssh는 암호화된 원격 로그인과 명령 실행을 제공한다. 공개 키 인증, 포트 전달, 에이전트와 다양한 암호화 설정을 지원하며 서버 측의 sshd와 함께 OpenSSH를 구성한다.

scpsftp는 SSH 연결을 통해 파일을 전송한다. 현대 OpenSSH에서 scp 명령은 보안과 파일 이름 처리 문제를 줄이기 위해 SFTP 프로토콜을 기본 전송 방식으로 사용할 수 있다.

기본 ftp 프로그램은 전통적인 FTP 클라이언트 이름을 사용하지만 HTTP와 HTTPS를 통한 파일 다운로드에도 사용된다. 설치·업그레이드 스크립트와 관리 작업에서 비대화형 다운로드 도구로 활용할 수 있다.

nc는 TCP와 UDP 연결을 만들거나 특정 포트에서 연결을 기다리는 범용 네트워크 도구다. 서비스 연결 시험, 단순한 데이터 전달과 UNIX 도메인 소켓 진단 등에 사용할 수 있다.

telnet은 Telnet 프로토콜 접속 외에도 암호화되지 않은 TCP 서비스의 대화형 시험에 사용할 수 있지만, 원격 로그인에는 평문 Telnet보다 SSH가 사용된다.

pingping6는 ICMP 응답과 왕복 시간을 확인한다. 응답이 없다고 해서 반드시 호스트가 꺼져 있는 것은 아니며 방화벽이나 네트워크 정책이 ICMP를 차단할 수 있다.

traceroutetraceroute6는 목적지까지의 경로에서 응답하는 중간 홉을 확인한다. 실제 전달 경로는 비대칭일 수 있고 일부 라우터가 응답하지 않을 수 있으므로 출력이 전체 경로를 완전하게 보여준다고 볼 수는 없다.

DNS 조회에는 dig, hostnslookup 계열 도구를 사용할 수 있다. 로컬 해석기 설정과 별개로 특정 DNS 서버에 직접 질의하여 레코드와 응답 상태를 확인한다.

ifconfig는 인터페이스 주소, 링크 상태, 무선 네트워크, 가상 인터페이스와 여러 장치 속성을 관리한다. route는 라우팅 테이블, netstat는 소켓·경로·프로토콜 통계를 표시한다.

arpndp는 각각 IPv4 ARP와 IPv6 Neighbor Discovery 관련 캐시를 확인하고 관리한다. 일반적인 자동 동작 외에 진단과 정적 항목 관리에 사용할 수 있다.

tcpdump는 네트워크 인터페이스를 통과하는 패킷을 캡처하고 헤더를 해석한다. BPF 필터 표현식으로 필요한 트래픽만 선택할 수 있으며, PF 로그 인터페이스의 패킷을 조사하는 데에도 사용한다.

relayd, httpd, acme-client, smtpctl, bgpctl, iked와 여러 네트워크 서버·관리 프로그램도 기본 시스템에 포함된다. 이들은 모든 설치에서 자동 실행되는 것이 아니라 관리자가 필요한 서비스를 활성화하고 설정한다.

시스템 초기화

OpenBSD의 사용자 공간 초기화는 커널이 첫 번째 프로세스로 /sbin/init을 실행하면서 시작된다. init은 PID 1을 가지며 시스템 부팅 상태, 터미널 로그인과 종료 과정을 관리한다.[137]

커널이 부팅을 마치면 루트 파일 시스템을 사용 가능한 상태로 만들고 init을 실행한다. init은 시스템이 단일 사용자 모드인지 다중 사용자 모드인지에 따라 이후 절차를 결정한다.

단일 사용자 모드에서는 제한된 관리 셸을 실행하여 파일 시스템 검사, 암호 복구와 설정 수정을 수행할 수 있다. 네트워크 서비스와 일반 로그인 환경은 기본적으로 시작되지 않는다.

다중 사용자 부팅에서는 /etc/rc가 실행된다. rc 스크립트는 파일 시스템 확인과 마운트, 호스트 이름, 네트워크, 커널 설정, 장치 준비와 시스템 데몬 시작을 정해진 순서로 수행한다.[138]

부팅 설정의 기본값은 /etc/rc.conf에 정의되고 관리자의 변경은 /etc/rc.conf.local에 기록된다. 기본 파일을 직접 수정하면 업그레이드와 비교가 어려워질 수 있으므로 rcctl을 통한 로컬 설정이 권장된다.

각 데몬의 시작·종료 동작은 /etc/rc.d의 스크립트와 공통 함수인 rc.subr에 정의된다. 기본 시스템 서비스와 패키지 서비스가 같은 rcctl 관리 인터페이스를 사용할 수 있다.

네트워크 인터페이스는 /etc/hostname.if 형식의 파일과 netstart를 통해 구성된다. 물리 인터페이스, 무선, VLAN, 브리지, CARP와 여러 가상 인터페이스의 설정 순서가 부팅 과정에 반영된다.

/etc/rc.local은 기본 부팅 과정 뒤에 실행할 로컬 명령을 기록할 수 있고, /etc/rc.shutdown은 종료 시 추가 작업을 수행할 수 있다. 그러나 일반 서비스는 임의 명령보다 rc.d 스크립트와 rcctl로 관리하는 편이 상태 확인과 종료 처리를 일관되게 할 수 있다.

부팅이 완료되면 init/etc/ttys에 정의된 터미널에 getty를 실행한다. getty는 터미널 속성을 설정하고 로그인 이름을 받은 뒤 login을 실행한다.

시스템 종료 요청이 들어오면 서비스에 종료 시그널을 보내고 rc.shutdown과 관련 절차를 수행한 뒤 파일 시스템을 동기화한다. PID 1이 예기치 않게 종료되면 시스템 전체가 정상적으로 계속 동작할 수 없으므로 커널에서 특별하게 취급된다.

OpenBSD의 초기화 체계는 복잡한 동적 서비스 그래프보다 명시적인 부팅 순서와 텍스트 설정을 중심으로 한다. 서비스 시작 조건과 자원 제한은 rc 스크립트, rcctl 설정과 로그인 클래스로 표현한다.

cron과 주기적 작업

cron은 지정된 시간이나 반복 주기에 명령을 실행하는 데몬이다. 시스템 유지보수, 백업, 로그 처리, 인증서 갱신과 사용자별 자동 작업을 예약하는 데 사용된다.

cron 데몬은 부팅 과정에서 시작되며 사용자와 시스템의 crontab 파일을 읽는다. 일정이 도래하면 해당 사용자의 권한과 환경으로 셸 명령을 실행한다.[139]

사용자별 일정은 crontab 명령으로 편집한다. crontab -e는 현재 사용자의 일정을 편집하고, crontab -l은 내용을 표시하며, crontab -r은 제거한다.

root는 crontab -u 사용자를 이용해 다른 사용자의 일정을 관리할 수 있다. crontab 파일을 일반 편집기로 직접 수정하기보다 crontab 명령을 사용하면 설치와 문법 처리 과정이 일관되게 이루어진다.

일반 crontab 항목은 분, 시, 일, 월, 요일과 실행할 명령으로 구성된다. 별표는 모든 값을 뜻하고 목록, 범위와 간격을 사용하여 반복 주기를 표현할 수 있다.

@reboot, @daily, @weekly, @monthly와 같은 특수 문자열을 사용할 수 있다. 실제 지원 문법과 실행 시점은 crontab(5) 매뉴얼을 기준으로 해야 한다.[140]

OpenBSD는 /etc/daily, /etc/weekly/etc/monthly 스크립트를 통해 정기적인 시스템 유지보수 작업을 수행한다. 파일 시스템 상태, 보안 관련 변경, 로그와 여러 통계를 점검하여 관리자에게 보고할 수 있다.

관리자는 /etc/daily.local, /etc/weekly.local/etc/monthly.local에 로컬 작업을 추가할 수 있다. 기본 시스템 스크립트를 직접 수정하지 않고도 정기 점검과 백업 명령을 통합할 수 있다.

cron에서 실행되는 명령은 대화형 로그인 셸보다 제한된 환경을 가진다. PATH, 현재 디렉터리, 터미널과 사용자 프로필을 가정하지 말고 필요한 경로와 환경 변수를 명시해야 한다.

명령의 표준 출력과 표준 오류는 설정에 따라 사용자에게 메일로 전달될 수 있다. 불필요한 출력은 리디렉션할 수 있지만, 오류까지 모두 버리면 작업 실패를 발견하기 어려워질 수 있다.

같은 작업이 이전 실행을 끝내기 전에 다시 시작될 수 있는 경우 잠금 파일, flock에 해당하는 별도 방식 또는 프로그램 내부의 중복 실행 방지가 필요하다. cron 자체는 일반적으로 작업의 완료 여부를 기다려 다음 일정을 자동으로 조정하는 작업 큐가 아니다.

한 번만 또는 특정 시점에 실행할 작업에는 atbatch를 사용할 수 있다. at은 지정한 시각, batch는 시스템 부하 조건을 고려한 시점에 작업을 실행 대기열에 넣는다.

로그 관리

OpenBSD의 시스템 로그는 주로 syslogd가 수집하고 분류한다. 커널, 데몬과 응용 프로그램은 syslog 인터페이스 또는 로그 소켓으로 메시지를 보내며, syslogd는 설정에 따라 파일, 콘솔, 사용자나 원격 로그 서버로 전달한다.[141]

로그 정책은 /etc/syslog.conf에 정의된다. 메시지는 facility와 priority의 조합으로 분류되며, 인증, 메일, 데몬, 커널과 일반 사용자 메시지를 서로 다른 파일이나 대상으로 보낼 수 있다.

일반적인 로그 파일은 /var/log 아래에 저장된다. 시스템 메시지, 인증·권한 상승 기록, 메일, 데몬과 보안 관련 로그는 설정에 따라 별도 파일로 나뉜다.

logger 명령은 셸이나 스크립트에서 syslog 메시지를 생성한다. 시설과 우선순위, 태그를 지정하여 자동화 작업의 결과를 시스템 로그 체계에 통합할 수 있다.

syslogd는 로컬 UNIX 도메인 소켓에서 메시지를 받고 커널 로그 장치도 읽는다. 네트워크 로그 수신과 전달을 구성할 수 있지만 외부 입력과 로그 위조, 전송 보호를 고려해야 한다.

OpenBSD의 syslogd는 TLS를 이용한 원격 로그 전송과 수신을 지원할 수 있다. 인증서와 설정을 통해 로그가 신뢰되지 않는 네트워크에서 평문으로 노출되거나 임의 서버로 전달되는 위험을 줄일 수 있다.

로그 파일은 계속 증가하므로 newsyslog가 일정 크기나 시간이 되면 기존 파일의 이름을 바꾸고 새 파일을 만든다. 오래된 로그는 압축하거나 정해진 개수만 남기고 삭제할 수 있다.[142]

로그 순환 정책은 /etc/newsyslog.conf에 정의된다. 파일 소유자와 그룹, 권한, 유지할 세대 수, 순환 조건, 압축 여부와 순환 후 보낼 시그널을 지정할 수 있다.

실행 중인 데몬이 로그 파일을 열어 둔 경우 단순히 파일 이름만 변경하면 계속 이전 파일에 기록할 수 있다. newsyslog는 설정에 따라 데몬에 시그널을 보내 새 로그 파일을 다시 열게 한다.

정기적인 로그 순환은 cron과 시스템 유지보수 작업을 통해 실행된다. 관리자는 서비스별 로그를 추가할 때 /etc/syslog.conf/etc/newsyslog.conf의 수집·순환 정책을 함께 구성해야 한다.

dmesg는 커널 메시지 버퍼를 표시하며 부팅 중 인식된 장치와 커널 오류를 확인하는 데 사용한다. 다만 메시지 버퍼는 영구 저장소가 아니므로 장기적인 기록은 시스템 로그 파일을 확인해야 한다.

last, lastlogin과 로그인 관련 데이터베이스는 사용자 로그인·로그아웃 이력을 보여준다. doas와 인증 프로그램의 기록은 설정된 보안 로그에서 확인할 수 있다.

로그 파일에는 사용자 이름, 주소, 명령, 오류 내용과 인증 정보 같은 민감한 데이터가 포함될 수 있다. 파일 권한, 보관 기간, 원격 전송과 백업 정책을 서비스의 보안 요구에 맞게 설정해야 한다.

로그는 문제가 발생한 뒤 원인을 분석하는 자료이지만 무제한으로 보관할 수는 없다. 디스크 공간, 개인정보, 침해 대응과 운영상의 필요를 함께 고려하여 보관 기간과 압축·삭제 정책을 정해야 한다.

소프트웨어 관리

OpenBSD의 소프트웨어 관리는 커널과 기본 명령어, 시스템 라이브러리로 구성된 기본 시스템과 제3자 프로그램으로 구성된 외부 소프트웨어를 명확하게 구분한다. 기본 시스템은 OpenBSD 정식 릴리스의 설치 파일 세트와 시스템 업그레이드 절차를 통해 관리하고, 외부 소프트웨어는 포트 컬렉션에서 생성된 바이너리 패키지를 pkg_add, pkg_deletepkg_info로 관리한다.

OpenBSD에서 포트와 패키지는 서로 경쟁하는 별개의 소프트웨어 배포 방식이 아니다. 포트는 제3자 소프트웨어를 OpenBSD에 맞게 내려받고 수정·컴파일하여 패키지로 만드는 빌드 기반이며, 패키지는 그 과정의 최종 결과물이다. 일반 사용자는 포트를 직접 빌드하기보다 공식 저장소에서 제공하는 바이너리 패키지를 설치하는 것이 권장된다.[143]

패키지 시스템은 설치 파일, 의존 관계, 설정 예제와 제거 정보를 데이터베이스에 기록한다. 설치 중에는 기존 파일과의 충돌, 패키지 서명, 아키텍처와 의존성을 확인하고, 제거할 때에는 다른 패키지가 해당 패키지를 필요로 하는지와 설치 뒤 수정된 파일이 있는지를 검사한다.

OpenBSD의 패키지는 기본 시스템과 같은 소스 트리에서 개발되는 것은 아니며, 수많은 외부 프로젝트의 코드를 포함한다. 포트 개발자는 OpenBSD에서 빌드하고 실행되도록 패치와 패키징을 관리하지만 모든 외부 소프트웨어가 OpenBSD 기본 시스템과 같은 수준으로 코드 감사를 받는 것은 아니다.

기본 시스템과 외부 소프트웨어의 구분

OpenBSD의 기본 시스템에는 커널, C 라이브러리, 기본 셸, 파일·프로세스 관리 명령, 네트워크 도구, 여러 시스템 데몬과 매뉴얼 페이지가 포함된다. 이들은 OpenBSD 프로젝트의 기본 소스 트리에서 함께 개발되고 하나의 정식 릴리스로 배포된다.

기본 시스템은 설치 파일 세트로 나뉜다. baseXX.tgz, compXX.tgz, manXX.tgz와 X Window System 관련 파일 세트가 대표적이며, 여기서 XX는 릴리스 번호를 나타낸다.

이 파일 세트는 이름이 압축 아카이브 형태라고 해서 OpenBSD 패키지는 아니다. pkg_add 매뉴얼은 baseXX.tgzcompXX.tgz 같은 시스템 배포 파일을 패키지로 설치할 수 없다고 명시한다.[144]

기본 시스템의 설치와 정식 릴리스 업그레이드는 설치 프로그램, sysupgrade, 설치 램디스크와 파일 세트 배포 절차를 통해 수행한다. 같은 릴리스 안에서 제공되는 보안·신뢰성 수정은 syspatch로 적용할 수 있다.

외부 소프트웨어에는 웹 브라우저, 데스크톱 환경, 데이터베이스, 추가 프로그래밍 언어, 대규모 서버 프로그램과 OpenBSD 기본 시스템에 포함되지 않은 라이브러리가 해당한다. 이러한 프로그램은 일반적으로 패키지 저장소에서 설치한다.

기본 시스템의 실행 파일은 주로 /bin, /sbin, /usr/bin/usr/sbin에 설치된다. 외부 패키지의 실행 파일과 라이브러리는 주로 /usr/local/bin, /usr/local/sbin, /usr/local/lib/usr/local/share에 설치된다.

이러한 디렉터리 분리는 제3자 프로그램이 기본 시스템의 파일을 임의로 덮어쓰는 상황을 줄인다. 기본 C 라이브러리와 시스템 도구는 /usr 계층에 유지하고, 외부 프로그램과 해당 라이브러리는 /usr/local에서 별도로 관리한다.

패키지로 설치한 설정 파일은 프로그램에 따라 /etc 또는 /etc 아래의 하위 디렉터리에 놓일 수 있다. 설정 예제는 /usr/local/share/examples에 제공되며, 관리자가 실제 사용할 설정을 복사하거나 패키지 설치 스크립트가 적절한 위치에 초기 파일을 만들 수 있다.

설치된 외부 패키지의 관리 정보는 기본적으로 /var/db/pkg에 저장된다. 기본 시스템 파일은 이 데이터베이스에 패키지로 등록되지 않으므로 pkg_infopkg_delete의 관리 대상이 아니다.

기본 시스템과 패키지는 업데이트 체계도 분리된다. syspatch는 기본 시스템을 수정하고, pkg_add -u는 설치된 외부 패키지를 갱신한다. 어느 한쪽을 갱신했다고 다른 계층까지 자동으로 최신 상태가 되는 것은 아니다.

새 OpenBSD 릴리스로 업그레이드하면 기본 시스템과 외부 패키지의 라이브러리 인터페이스가 달라질 수 있다. 따라서 운영체제 업그레이드 뒤에는 새 릴리스용 패키지 저장소를 사용해 외부 패키지도 함께 갱신해야 한다.

패키지 시스템

OpenBSD 패키지는 제3자 소프트웨어의 실행 파일, 라이브러리, 매뉴얼, 공유 데이터와 설치 정보를 하나의 배포 단위로 묶은 바이너리 아카이브다. 일반적으로 .tgz 확장자를 사용하며 패키지 이름에는 프로그램 이름, 버전과 패키징 수정 번호가 포함될 수 있다.

패키지는 포트 인프라와 pkg_create를 통해 만들어진다. 수동으로 패키지를 직접 구성할 수도 있지만, 공식 문서는 일관된 의존 관계와 패키징 규칙을 위해 포트 인프라를 사용하는 것을 권장한다.[145]

패키지에는 실제 설치 파일 외에도 packing-list가 포함된다. 이 목록은 어느 파일과 디렉터리를 만들고, 어떤 의존 패키지가 필요하며, 어떤 설정 예제와 등록 작업을 수행해야 하는지를 정의한다.

패키지 이름은 프로그램의 기본 이름인 stem과 버전, flavor, subpackage, 패키지 수정 번호로 구성될 수 있다. 같은 프로그램이라도 기능 조합이나 언어 지원, 그래픽·명령줄 구성에 따라 여러 패키지로 나뉠 수 있다.

flavor는 같은 포트를 서로 다른 빌드 옵션으로 만드는 방법이다. 예를 들어 특정 GUI 지원, 추가 인터프리터 또는 선택적 기능을 포함한 변형을 별도 패키지로 제공할 수 있다.

subpackage는 하나의 소스 빌드 결과를 여러 설치 단위로 나눈다. 실행 프로그램, 개발 헤더, 문서, 서버와 클라이언트 또는 디버그 심볼을 서로 다른 패키지로 분리할 수 있다.

패키지 시스템은 의존 관계를 추적한다. 사용자가 프로그램 하나를 설치하면 해당 프로그램에 필요한 라이브러리와 도구를 함께 설치하고, 어떤 패키지가 다른 패키지를 필요로 하는지 데이터베이스에 기록한다.

사용자가 직접 요청한 패키지와 의존성으로 자동 설치된 패키지도 구분할 수 있다. 이 정보는 실제로 필요한 최상위 프로그램과 더 이상 필요하지 않을 수 있는 의존 패키지를 판단하는 데 사용된다.

패키지는 현재 운영체제 릴리스와 하드웨어 아키텍처에 맞아야 한다. amd64용 패키지를 arm64에 설치할 수 없으며, 정식 릴리스용 패키지와 -current 스냅샷용 패키지를 임의로 섞어 사용하는 것도 지원되지 않는다.

패키지 저장소는 릴리스와 아키텍처별 디렉터리로 나뉜다. 시스템은 /etc/installurl에 기록된 OpenBSD 미러를 바탕으로 자신의 버전과 아키텍처에 맞는 패키지 위치를 계산한다.

패키지 설치와 제거 기록은 syslog에 남을 수 있다. 관리자는 어떤 패키지가 언제 추가·갱신·삭제되었는지 시스템 로그와 패키지 데이터베이스를 통해 확인할 수 있다.

pkg_add

pkg_add는 OpenBSD 패키지를 설치하고 기존 패키지를 갱신하는 기본 명령이다. 패키지 이름, 로컬 패키지 파일 또는 저장소의 위치를 받아 의존성, 충돌, 서명과 기존 설치 상태를 검사한 뒤 파일을 배치한다.[146]

패키지 이름에 정확한 버전을 지정하지 않으면 pkg_add는 저장소에서 현재 시스템에 적합한 후보를 검색한다. 동일한 이름의 여러 flavor나 변형이 존재하면 대화형 환경에서 사용자에게 선택을 요청할 수 있다.

패키지의 의존성이 설치되어 있지 않으면 필요한 패키지를 재귀적으로 찾고 먼저 설치한다. 의존 관계가 충족되지 않거나 적합한 패키지가 저장소에 없으면 설치를 중단한다.

설치 전에는 패키지 안에 포함된 파일이 기존 기본 시스템이나 다른 패키지의 파일과 충돌하는지 검사한다. 기존 파일을 무조건 덮어쓰는 대신 충돌을 오류로 보고하여 서로 다른 패키지가 같은 경로를 소유하는 상황을 방지한다.

패키지가 서명되어 있으면 pkg_add는 압축을 풀고 파일을 설치하기 전에 서명과 압축 패키지 데이터가 일치하는지 검증한다. 기본적으로 신뢰할 수 없는 출처의 서명되지 않은 패키지는 거부한다.[147]

패키지가 실제로 설치되면 파일과 디렉터리를 배치하고 등록 스크립트와 설정 파일 처리를 수행한다. 설치된 패키지의 packing-list, 설명, 의존 관계와 파일 체크섬은 /var/db/pkg의 전용 디렉터리에 기록된다.

패키지에 샘플 설정이 포함된 경우 기존 관리자의 설정을 무조건 덮어쓰지 않도록 처리된다. 최초 설치에서는 기본 설정이 생성될 수 있지만, 이후 업데이트에서는 로컬 변경 사항을 보존하거나 새 샘플 파일을 별도로 제공한다.

pkg_add -i는 대화형 선택을 명시적으로 사용할 수 있고, -I는 설치 후 표시되는 메시지와 질문을 줄이는 등 실행 방식을 조정한다. 자동화 환경에서는 후보가 여러 개인 경우를 피하기 위해 정확한 패키지 이름과 비대화형 동작을 고려해야 한다.

이미 설치된 패키지 이름을 pkg_add에 다시 지정하면 해당 패키지를 사용자가 직접 설치한 패키지로 표시할 수 있다. 의존성으로 설치되었던 패키지를 명시적인 유지 대상으로 바꾸는 데 활용된다.

패키지 설치 중 인터럽트가 발생하면 패키지 시스템은 부분 설치 상태를 기록하여 다음 검사와 복구에서 확인할 수 있게 한다. 단순히 일부 파일만 배치된 채 정상 패키지로 등록되는 상황을 줄이기 위한 처리다.

pkg_add는 기본 시스템 배포 파일을 설치하는 명령이 아니다. OpenBSD 커널이나 baseXX.tgzpkg_add로 갱신하지 않으며, 운영체제와 외부 소프트웨어의 관리 경계를 유지한다.

pkg_delete와 pkg_info

pkg_deletepkg_add로 설치한 패키지를 제거하는 명령이다. 패키지 데이터베이스의 packing-list를 읽어 설치했던 파일과 등록 정보를 제거하고 의존 관계를 갱신한다.[148]

패키지를 제거하려 할 때 다른 설치된 패키지가 해당 패키지에 의존하고 있으면 경고하거나 제거를 거부할 수 있다. 의존 패키지를 강제로 제거하면 남아 있는 프로그램이 필요한 라이브러리나 파일을 찾지 못할 수 있다.

패키지가 설치했던 파일이 이후 관리자가 수정한 상태라면 pkg_delete는 설치 당시 체크섬과 현재 파일을 비교할 수 있다. 변경된 파일은 일반적으로 자동 삭제하지 않고 경고하거나 남겨 두어 로컬 설정을 보호한다.[149]

설정 파일과 데이터 디렉터리처럼 패키지 제거 뒤에도 보존할 필요가 있는 항목은 packing-list 정책에 따라 남을 수 있다. 따라서 패키지가 삭제되었다고 관련 사용자 데이터와 설정이 모두 제거되었다고 단정할 수 없다.

더 이상 다른 패키지가 필요로 하지 않는 자동 설치 의존 패키지는 별도로 정리할 수 있다. 다만 해당 패키지를 사용자가 직접 활용하고 있는지 확인하지 않고 일괄 삭제하면 필요한 도구를 잃을 수 있다.

pkg_info는 설치된 패키지 또는 패키지 파일의 정보를 표시한다. 패키지 이름, 설명, 설치 파일, 의존 관계, 필요한 패키지와 설치 이유 등을 확인할 수 있다.[150]

인수 없이 pkg_info를 실행하면 설치된 패키지 목록을 확인할 수 있다. 옵션을 사용하면 패키지의 전체 설명, packing-list, 의존성, 파일 목록과 설치 경로를 자세히 볼 수 있다.

사용자가 직접 설치한 패키지만 표시하는 기능은 시스템을 재구성하거나 다른 컴퓨터에 비슷한 소프트웨어 환경을 만들 때 유용하다. 의존 패키지를 모두 직접 나열하지 않고 최상위 프로그램 목록만 보관할 수 있다.

특정 파일이 어느 패키지에 속하는지 확인할 때에는 설치된 패키지 정보나 패키지 위치 데이터베이스를 조회할 수 있다. pkg_mklocatedb와 관련 도구는 패키지 저장소의 파일 목록을 검색 가능한 데이터베이스로 만들 수 있다.[151]

pkg_check는 설치된 패키지 데이터베이스와 실제 파일의 일관성을 검사한다. 누락된 파일, 깨진 의존 관계, 부분 설치와 잘못된 등록 상태를 찾고 일부 문제를 복구하는 데 사용한다.

패키지 제거와 정보 조회는 기본 시스템 파일에는 적용되지 않는다. /bin/ls나 기본 C 라이브러리가 어떤 패키지에 속하는지 pkg_info로 조회할 수 없는 것은 이들이 외부 패키지가 아니라 OpenBSD 기본 시스템이기 때문이다.

패키지 업데이트

설치된 외부 패키지는 pkg_add -u로 갱신한다. 이 명령은 현재 설치된 패키지와 저장소의 후보를 비교하고 호환되는 새 버전이나 패키징 수정판으로 교체한다.

업데이트 과정에서도 일반 설치와 마찬가지로 서명, 의존성, 충돌과 아키텍처를 검사한다. 새 패키지가 기존 패키지를 대체할 수 있는지 확인하고 관련 의존 패키지의 업데이트 집합을 계산한다.

업데이트할 패키지가 공유 라이브러리를 제공하면 해당 라이브러리를 사용하는 다른 패키지도 함께 갱신해야 할 수 있다. 하나의 라이브러리만 새 버전으로 바꾸고 의존 프로그램을 그대로 두면 실행 파일이 필요한 라이브러리 버전을 찾지 못할 수 있다.

OpenBSD 정식 릴리스용 저장소에는 릴리스 이후 중요한 수정이 반영된 -stable 패키지가 제공될 수 있다. 특히 보안 영향을 받는 주요 프로그램은 정식 릴리스 전체를 기다리지 않고 갱신된 패키지가 배포될 수 있다.

quirks 패키지는 패키지 시스템의 호환성 처리와 알려진 문제에 관한 규칙을 제공한다. pkg_add는 업데이트 과정에서 quirks를 우선 갱신하여 이름 변경, 패키지 분할·병합과 문제가 있는 과거 패키지를 처리할 수 있다.[152]

패키지를 업데이트해도 이미 실행 중인 프로세스가 새 실행 파일과 라이브러리를 자동으로 사용하는 것은 아니다. 장기간 실행되는 데몬과 데스크톱 프로그램은 재시작해야 새 코드가 실제 실행된다.

OpenBSD 정식 릴리스에서 다음 릴리스로 업그레이드할 때에는 먼저 기본 시스템을 갱신한 뒤 pkg_add -u로 패키지를 새 릴리스용으로 교체하는 흐름을 따른다. 이전 릴리스 저장소와 새 기본 시스템을 장기간 혼합해서는 안 된다.

-current 시스템은 정식 릴리스보다 인터페이스 변경이 잦다. 스냅샷 기본 시스템과 패키지는 서로 가까운 시점의 빌드를 사용해야 하며, 오래된 스냅샷에서 패키지만 최신으로 갱신하면 라이브러리 불일치가 생길 수 있다.

모든 패키지를 무조건 최신 버전으로 올리는 것이 항상 충분한 관리 방법은 아니다. 업데이트 뒤 설정 파일 변경, 서비스 이름, 기본 옵션과 데이터베이스 형식 전환이 필요한지 패키지 설치 메시지와 업스트림 릴리스 정보를 확인해야 한다.

기본 시스템의 보안 패치는 pkg_add -u가 아니라 syspatch로 관리한다. 반대로 syspatch는 웹 브라우저나 패키지 데이터베이스 서버 같은 외부 프로그램을 갱신하지 않는다.

포트 컬렉션

OpenBSD 포트 컬렉션은 제3자 소프트웨어를 OpenBSD에서 빌드하고 바이너리 패키지로 만들기 위한 메타데이터와 빌드 규칙의 집합이다. 일반적으로 /usr/ports에 배치되며 분야별 디렉터리 아래에 각 프로그램의 포트가 존재한다.[153]

포트에는 프로그램 소스 코드 전체를 직접 포함하지 않는 경우가 많다. 대신 원본 배포 파일의 위치, 크기와 체크섬, 빌드 방법, 의존성, OpenBSD용 패치와 패키지 파일 목록을 기록한다.

각 포트의 Makefile은 프로그램 이름, 버전, 카테고리, 홈페이지, 라이선스, 빌드 방식과 의존 관계를 정의한다. 공통 작업은 bsd.port.mk 인프라가 처리한다.

distinfo는 다운로드할 원본 파일의 체크섬과 크기를 기록한다. 원격 서버의 파일이 포트 작성 시 검증된 내용과 다르면 빌드를 중단하여 변경되거나 손상된 소스를 그대로 사용하는 것을 방지한다.

patches 디렉터리에는 OpenBSD에서 컴파일하거나 안전하게 실행하기 위해 적용하는 수정 사항이 들어갈 수 있다. 업스트림의 플랫폼 가정, 컴파일러 차이, 파일 경로, 권한과 보안 기능 적용을 조정한다.

pkg/DESCR은 패키지 설명을 제공하고, pkg/PLIST는 최종 패키지에 포함할 파일과 설치 동작을 정의한다. 실제 빌드 결과와 PLIST가 일치하지 않으면 패키지 생성 또는 검사 과정에서 문제가 드러날 수 있다.

포트는 make fetch, checksum, extract, patch, configure, build, fake, package와 같은 단계로 처리된다. fake 단계는 실제 시스템에 바로 설치하지 않고 임시 디렉터리에 설치하여 최종 패키지 파일 목록을 만든다.

이 가상 설치 단계 덕분에 포트 빌드가 시스템 파일을 직접 임의 변경하는 것을 줄이고, 패키지에 포함될 결과를 먼저 검사할 수 있다. 실제 시스템 설치는 생성된 패키지를 pkg_add가 처리한다.

포트 컬렉션은 사용 중인 OpenBSD 버전과 일치해야 한다. 정식 릴리스 시스템에는 해당 릴리스의 포트 트리를 사용하고, -current 시스템에는 현재 소스와 호환되는 포트 트리를 사용해야 한다.

포트에서 직접 빌드하려면 컴파일러 파일 세트, 소스 다운로드 공간, 빌드 디렉터리와 충분한 메모리가 필요하다. 대형 프로그램은 빌드 시간이 길고 여러 의존 포트를 추가로 컴파일할 수 있다.

포트 빌드는 일반 사용자보다 별도의 빌드 사용자와 제한된 환경에서 수행하는 것이 좋다. 공식 패키지 빌드 인프라는 대량의 포트를 자동으로 빌드하고 의존 관계와 실패를 추적하도록 구성된다.

포트 트리에 항목이 있다고 모든 플랫폼에서 공식 바이너리 패키지가 제공되는 것은 아니다. 빌드 실패, 라이선스의 바이너리 재배포 제한, 아키텍처 지원 부족과 자원 제약으로 특정 패키지가 제외될 수 있다.

ports와 packages의 관계

포트는 소프트웨어를 빌드하는 조리법이고, 패키지는 그 조리법으로 만들어진 설치 가능한 결과물이다. OpenBSD 포트 체계는 최종적으로 바이너리 패키지를 생성하는 것을 중심으로 설계되어 있다.

포트에서 make install을 실행하더라도 일반적으로 빌드 결과를 파일 시스템에 직접 복사하는 것이 아니다. 먼저 패키지를 만든 뒤 pkg_add를 호출하여 설치하므로, 직접 빌드한 프로그램도 패키지 데이터베이스에 등록된다.

이 구조 덕분에 포트에서 직접 만든 프로그램도 공식 바이너리 패키지와 같은 pkg_info, pkg_delete와 의존성 관리 체계를 사용할 수 있다. 소스에서 빌드했다는 이유로 제거 방법이 달라지지 않는다.

OpenBSD 포트 문서는 일반 사용자에게 패키지 사용을 권장한다. 공식 패키지는 이미 빌드와 패키징 검사를 거쳤으며 사용자가 모든 의존 프로그램을 직접 컴파일할 필요가 없다.[154]

포트를 직접 빌드하는 경우는 공식 패키지가 제공되지 않거나, 로컬 패치를 적용하거나, 특정 flavor와 빌드 구성을 변경해야 할 때가 중심이다. 단순히 소프트웨어를 사용하려는 목적이라면 패키지가 더 일관되고 빠르다.

하나의 포트는 하나 이상의 패키지를 생성할 수 있다. multi-package 포트는 같은 소스 빌드에서 프로그램 본체, 라이브러리, 문서, 서버와 클라이언트를 별도의 패키지로 만든다.

같은 포트에서 여러 flavor를 만들면 각 flavor마다 이름과 의존성이 다른 패키지가 생성된다. 사용자는 포트의 내부 빌드 옵션이 아니라 최종 패키지 이름을 선택하여 원하는 변형을 설치한다.

포트 유지보수자는 최종 패키지를 실제로 설치하고 제거하여 파일 목록, 설정, 의존성과 제거 동작을 검사해야 한다. 포팅 가이드는 make package, make install, make uninstall 또는 pkg_add·pkg_delete를 이용한 시험을 권장한다.[155]

공식 패키지와 로컬 포트 빌드 패키지를 혼합할 수는 있지만 빌드 옵션, 라이브러리 버전과 시점이 달라질 수 있다. 특히 -current에서는 기본 시스템과 포트 트리, 설치 패키지의 시점을 맞춰야 한다.

포트를 직접 수정한 경우 이후 공식 패키지 업데이트가 로컬 변경을 대체할 수 있다. 로컬 패치와 flavor를 장기 유지하려면 자체 패키지 저장소와 빌드 기록을 관리하는 편이 안전하다.

포트 트리는 설치된 소프트웨어의 실행 시 필수 구성 요소가 아니다. 패키지를 빌드하고 설치한 뒤에는 일반적으로 /usr/ports가 없어도 설치된 프로그램을 실행하고 pkg_* 도구로 관리할 수 있다.

패키지 서명과 검증

OpenBSD 공식 바이너리 패키지는 암호학적 서명을 사용하여 배포 과정에서 패키지가 변조되지 않았는지 확인한다. pkg_add는 서명 검증에 실패하거나 신뢰할 수 없는 서명인 패키지를 기본적으로 거부한다.

패키지 서명은 OpenBSD의 signify 기반 형식을 사용한다. signify는 공개 키 서명을 만들고 검증하는 작은 도구로, OpenBSD 설치 파일 세트와 패치 검증에도 사용된다.[156]

현재 패키지 형식은 압축 데이터의 gzip 헤더에 서명을 포함할 수 있다. 이를 통해 pkg_add는 전체 패키지를 먼저 압축 해제하지 않고도 압축된 데이터 스트림을 읽으면서 서명을 검증할 수 있다.[157]

서명은 패키지를 만든 주체의 개인 키에 대응하는 공개 키로 검증한다. 정식 릴리스와 패키지 저장소에 사용할 신뢰된 공개 키는 기본 시스템과 함께 제공될 수 있다.

pkg_add는 압축 패키지 데이터가 서명된 내용과 일치하는지 확인한 뒤에만 파일을 풀어 설치한다. 전송 중 손상되거나 미러에서 내용이 변경된 패키지는 검증에 실패한다.[158]

기본적으로 서명되지 않은 패키지는 거부되지만, 관리자가 명시적으로 신뢰한 로컬 경로나 별도 옵션을 사용하면 로컬 패키지를 설치할 수 있다. 이 경우 패키지 출처와 빌드 환경의 신뢰성은 관리자가 직접 책임져야 한다.

로컬 패키지 저장소를 운영할 때에는 pkg_sign으로 패키지 컬렉션에 서명할 수 있다. 서명용 개인 키는 빌드·배포 서버와 분리하고 접근 권한을 제한해야 한다.[159]

서명 검증은 패키지가 서명된 뒤 변경되지 않았고 해당 키의 소유자가 만든 것임을 확인한다. 프로그램 자체에 보안 취약점, 악성 기능이나 잘못된 기본 설정이 없음을 보증하는 것은 아니다.

포트의 원본 소스 파일은 distinfo에 기록된 해시로 확인한다. 이는 업스트림에서 내려받은 파일이 포트 작성자가 검사한 파일과 같은지 확인하지만, 공식 바이너리 패키지 서명과는 다른 검증 단계다.

OpenBSD 패키지 체계는 오래된 문제가 있는 패키지를 제공하는 불완전한 미러에 대한 방어도 고려한다. quirks와 저장소 메타데이터를 통해 더 이상 안전하지 않거나 정상적으로 갱신해야 하는 과거 패키지를 식별할 수 있다.

HTTPS 미러를 사용하는 것은 전송 경로 보호에 도움이 되지만 패키지 서명을 대체하지 않는다. 서명은 미러와 전송 계층 바깥에서도 패키지 내용 자체를 검증하는 수단이다.

서드파티 소프트웨어의 격리

OpenBSD는 외부 패키지를 기본 시스템과 다른 디렉터리와 데이터베이스에서 관리하여 제3자 프로그램이 운영체제 핵심 파일과 섞이는 범위를 줄인다. 가장 기본적인 격리 경계는 /usr/local/var/db/pkg다.

패키지 실행 파일과 라이브러리는 주로 /usr/local 아래에 설치된다. 기본 시스템의 /usr/bin, /usr/sbin/usr/lib를 직접 교체하지 않으므로 운영체제 업그레이드와 패키지 제거의 경계를 유지할 수 있다.

패키지 설치 시 기존 파일과 충돌하면 pkg_add는 임의로 덮어쓰기보다 설치를 중단한다. 서로 다른 패키지나 로컬 파일이 같은 경로를 소유하는 상황을 조기에 드러낸다.[160]

패키지 제거 시에는 설치 당시 파일 체크섬을 비교하여 관리자가 수정한 파일을 보호한다. 외부 프로그램의 설정을 변경했더라도 패키지 삭제 과정이 해당 파일을 무조건 제거하지 않는다.

외부 서비스는 기본 시스템 서비스와 마찬가지로 rcctl과 rc 스크립트를 통해 실행할 수 있다. 패키지 전용 사용자, 로그인 클래스와 실행 옵션을 지정하여 일반 로그인 사용자나 root와 다른 권한으로 동작하게 할 수 있다.

패키지 데몬에는 전용 사용자와 그룹을 만들 수 있다. 서비스 데이터와 로그 디렉터리의 소유권을 해당 계정으로 제한하면 다른 패키지 서비스와 사용자 파일에 대한 접근 범위를 줄일 수 있다.

외부 프로그램도 OpenBSD의 pledgeunveil을 사용할 수 있다. 업스트림 소프트웨어가 직접 지원하지 않더라도 포트 패치로 적용되는 경우가 있으며, 프로그램의 시스템 호출과 파일 접근 범위를 제한한다.

chroot, 별도 routing domain, PF 정책과 전용 파일 시스템 파티션을 사용하면 네트워크 서비스의 접근 범위를 추가로 나눌 수 있다. 그러나 모든 패키지가 자동으로 이러한 환경에 배치되는 것은 아니므로 서비스별 구성이 필요하다.

패키지 설치 스크립트는 높은 권한으로 실행될 수 있으므로 신뢰되지 않는 패키지를 설치하는 것은 단순히 사용자 프로그램 하나를 실행하는 것보다 위험할 수 있다. 서명되지 않은 임의 패키지를 강제로 설치할 때에는 packing-list와 스크립트, 출처를 먼저 검토해야 한다.

OpenBSD 패키지 시스템은 컨테이너처럼 각 패키지에 독립된 커널·파일 시스템 이름 공간을 자동 제공하지 않는다. 디렉터리 분리와 파일 소유권, 패키지 데이터베이스를 통한 관리가 기본이며, 실행 시 격리는 운영체제의 권한·보안 기능과 서비스 설계를 결합해 구성한다.

외부 패키지는 OpenBSD 기본 시스템보다 훨씬 많은 코드와 의존성을 가져올 수 있다. 사용하지 않는 패키지와 서비스를 제거하고, 필요한 프로그램만 설치하며, 패키지 업데이트를 기본 시스템 패치와 별도로 관리하는 것이 공격 표면을 줄이는 기본 방법이다.

서드파티 소프트웨어의 격리는 프로그램을 완전히 신뢰할 수 없다는 가정에서 출발한다. 설치 위치, 전용 계정, 권한 제한, pledge, unveil, PF와 파일 시스템 권한을 여러 계층으로 적용하여 외부 프로그램의 결함이 기본 시스템 전체로 확산되는 범위를 줄인다.

설치와 시스템 관리

OpenBSD의 설치와 시스템 관리는 하나의 공통된 램디스크 환경을 중심으로 구성된다. 설치 매체에서 부팅하거나 기존 시스템의 /bsd.rd를 실행하면 메모리 안에서 동작하는 소형 OpenBSD 환경이 시작되며, 여기에서 새 설치, 업그레이드, 자동 설치 또는 복구용 셸을 선택할 수 있다.

설치 프로그램은 텍스트 기반의 질문·응답 방식으로 동작한다. 호스트 이름, 네트워크, 사용자 계정, 디스크 배치, 설치 파일 세트와 시간대를 순서대로 설정하며, 대부분의 일반적인 설치에서는 제안된 기본값을 받아들이는 것만으로 시스템을 구성할 수 있다.

설치가 끝난 뒤의 관리는 /etc 아래의 텍스트 설정 파일, rcctl, sysctl, pkg_*, syspatchsysupgrade 같은 기본 도구를 중심으로 이루어진다. 원격 관리에는 기본 시스템에 포함된 OpenSSH가 주로 사용되며, 복구가 필요할 때는 단일 사용자 모드나 bsd.rd의 셸을 사용할 수 있다.

설치 이미지

OpenBSD는 플랫폼별로 여러 종류의 설치 이미지를 제공한다. 모든 플랫폼이 같은 형식의 이미지를 지원하는 것은 아니며, 사용할 수 있는 매체와 부팅 방식은 각 아키텍처의 설치 문서를 따라야 한다.

amd64와 같은 일반적인 플랫폼에서는 설치용 USB 디스크 이미지와 CD·DVD용 ISO 이미지가 제공된다. USB 이미지는 저장 장치 전체에 기록한 뒤 펌웨어의 부트 메뉴에서 해당 장치를 선택해 시작한다.

작은 네트워크 설치 이미지에는 설치를 시작하는 데 필요한 커널과 최소 환경만 들어 있으며, 실제 기본 시스템 파일 세트는 설치 중 HTTP나 다른 지원 전송 방식으로 내려받을 수 있다. 전체 설치 ISO에는 일반적인 파일 세트가 포함되어 네트워크 연결 없이도 설치할 수 있다.

설치 환경의 중심은 bsd.rd라는 램디스크 커널이다. 이 커널은 자체 루트 파일 시스템과 설치 스크립트, 디스크·네트워크 관리에 필요한 소수의 명령을 포함하며 시스템 메모리에서 실행된다.[161]

이미 설치된 OpenBSD에서는 새 버전의 bsd.rd를 루트 파일 시스템에 내려받아 검증한 뒤 부트 로더에서 이를 선택할 수 있다. 따라서 설치나 업그레이드를 위해 항상 별도의 USB나 광학 매체가 필요한 것은 아니다.

네트워크 부팅을 지원하는 시스템은 PXE 또는 플랫폼별 네트워크 부트 방식을 이용할 수 있다. 부트 로더와 램디스크 커널을 네트워크에서 받은 뒤 설치 파일 세트도 HTTP 등의 방식으로 가져올 수 있다.

설치 이미지는 다운로드 뒤 체크섬과 서명을 확인하는 것이 권장된다. OpenBSD는 릴리스 파일의 체크섬 목록과 signify 서명을 제공하며, 공식 공개 키로 이미지가 배포 과정에서 변경되지 않았는지 확인할 수 있다.

설치 이미지를 USB 장치에 기록하는 작업은 일반 파일 복사와 다르다. 이미지 전체를 대상 장치에 기록하면 기존 파티션과 데이터가 덮어써질 수 있으므로 실제 장치 이름을 확인해야 한다.

각 릴리스와 아키텍처에는 INSTALL.<arch> 문서가 제공된다. 펌웨어 설정, 부트 로더, 콘솔, 디스크 구성과 알려진 제약은 공통 FAQ보다 이 문서에 더 구체적으로 설명될 수 있다.

설치 프로그램

OpenBSD 설치 환경을 부팅하면 설치, 업그레이드, 자동 설치와 셸 가운데 하나를 선택할 수 있다. 일반적인 새 설치에서는 Install을 선택하고, 기존 시스템의 릴리스를 올릴 때에는 Upgrade를 사용한다.

설치 프로그램은 그래픽 인터페이스가 아니라 터미널 기반의 대화형 스크립트다. 각 단계에서 현재 선택 가능한 값과 권장 기본값을 표시하며, 사용자는 값을 입력하거나 Enter를 눌러 기본값을 선택한다.

초기 단계에서는 키보드 배열, 시스템 호스트 이름, 네트워크 인터페이스와 주소 구성을 묻는다. DHCP를 사용할 경우 IP 주소, 기본 경로와 DNS 서버 정보의 상당 부분을 자동으로 받을 수 있다.

이후 root 암호, 일반 사용자 계정, sshd 활성화 여부, root의 SSH 로그인 허용 여부와 시간대를 설정한다. 플랫폼과 설치 선택에 따라 X Window System이나 직렬 콘솔에 관한 질문도 나타날 수 있다.

디스크를 선택하면 설치 프로그램은 플랫폼 파티션 테이블과 OpenBSD 디스크레이블을 구성한다. 자동 배치를 받아들이거나 대화형 편집기로 직접 파티션과 마운트 지점을 정할 수 있다.

파일 시스템 생성이 끝나면 설치할 파일 세트와 파일을 가져올 위치를 선택한다. 로컬 매체, 디스크, HTTP·HTTPS, FTP 또는 NFS 등 설치 환경과 플랫폼이 지원하는 경로를 사용할 수 있다.

기본 파일 세트에는 커널, 사용자 공간, 개발 도구, 매뉴얼과 Xenocara 관련 구성 요소가 포함된다. 필요한 파일 세트만 선택할 수 있지만 일반 설치에서는 기본 선택을 유지하는 편이 권장된다.

설치 프로그램은 파일 세트의 서명과 체크섬을 검증한 뒤 대상 파일 시스템에 압축을 해제한다. 이후 장치 파일, 호스트 키, 네트워크 설정, 부트 로더와 기본 설정을 생성한다.

사용자 정의 siteXX.tgz 파일 세트가 있으면 공식 파일 세트와 함께 설치할 수 있다. 설치 끝에는 install.site 스크립트를 실행하여 조직별 설정과 파일을 추가할 수도 있다.[162]

설치 프로그램은 복잡한 분기와 자동 감지보다 예측 가능한 질문 순서를 지향한다. 필요한 경우 이전 단계로 돌아가거나 설치를 중단하고 셸로 이동해 디스크와 네트워크 상태를 직접 확인할 수 있다.

디스크 구성

OpenBSD 설치에서 디스크 구성은 플랫폼의 외부 파티션 구조와 OpenBSD 디스크레이블이라는 두 계층으로 나뉠 수 있다. amd64와 같은 시스템에서는 먼저 GPT 또는 MBR에 OpenBSD용 영역을 만들고, 그 안을 다시 디스크레이블 파티션으로 분할한다.

설치 프로그램은 디스크 전체를 OpenBSD에 사용하는 자동 구성을 제공한다. UEFI 시스템에서는 일반적으로 EFI 시스템 파티션과 OpenBSD 영역을 만들고 필요한 부트 파일을 설치한다.

다른 운영체제와 디스크를 공유하려면 기존 파티션을 보존하면서 OpenBSD용 공간을 직접 만들어야 한다. 이 과정에서는 fdisk가 GPT·MBR 수준의 파티션을 관리한다.

OpenBSD 영역 안에서는 disklabela부터 p까지의 내부 파티션을 관리한다. a는 일반적으로 루트 파일 시스템, b는 스왑에 사용되고, c는 디스크 전체를 나타내므로 일반 파일 시스템으로 사용하지 않는다.

설치 프로그램의 자동 디스크레이블 배치는 디스크 크기를 기준으로 /, /home, /tmp, /usr, /usr/local/var 등을 여러 파티션으로 나눌 수 있다. 별도 파티션은 공간 고갈의 영향을 나누고 서로 다른 마운트 옵션을 적용하는 데 도움이 된다.

사용자는 자동 배치를 그대로 적용하거나 크기와 마운트 지점을 수정할 수 있다. 디스크레이블 편집기의 A 명령은 자동 배치를 만들고, n은 마운트 지점을 변경하며, z는 기존 레이블 항목을 지우고 새로 시작한다.

마운트 지점이 지정된 FFS 계통 파티션은 설치 과정에서 새 파일 시스템으로 포맷된다. 기존 데이터가 있는 파티션을 선택하면 내용이 파괴되므로 장치와 시작 위치, 크기를 확인해야 한다.[163]

소프트웨어 RAID나 전체 디스크 암호화를 사용할 때에는 설치 프로그램의 셸에서 먼저 softraid 볼륨을 만들 수 있다. 생성된 논리 디스크는 새로운 sd 장치로 나타나며 설치 프로그램은 이를 일반 설치 대상처럼 사용한다.

설치 뒤의 파일 시스템 마운트 정보는 /etc/fstab에 저장된다. 장치 번호 대신 DUID와 파티션 문자를 사용하면 디스크 검색 순서가 바뀌어도 같은 파일 시스템을 안정적으로 식별할 수 있다.

부트 로더가 필요로 하는 파티션과 파일 배치는 플랫폼마다 다르다. 다중 부팅, 암호화, RAID와 특수 펌웨어 환경에서는 해당 아키텍처의 설치 문서를 확인해야 한다.

네트워크 설정

설치 프로그램은 감지된 네트워크 인터페이스를 보여주고 각 인터페이스의 구성 여부를 묻는다. 인터페이스 이름은 사용되는 장치 드라이버와 번호에 따라 em0, igc0, iwx0처럼 표시된다.

유선 네트워크에서는 DHCP를 사용하거나 IPv4 주소, 넷마스크와 기본 게이트웨이를 직접 지정할 수 있다. IPv6는 자동 구성이나 정적 주소를 사용할 수 있다.

DHCP를 이용하면 호스트 이름, DNS 서버와 기본 경로 같은 정보도 함께 받을 수 있다. 자동으로 얻지 못한 값은 설치 프로그램이 별도로 질문한다.

무선 인터페이스에서는 사용 가능한 네트워크를 검색하고 네트워크 이름과 인증 정보를 입력할 수 있다. 장치가 펌웨어를 요구하지만 설치 이미지에 포함되지 않은 경우 유선 연결이나 별도 펌웨어 준비가 필요할 수 있다.

설치 중 설정한 네트워크 정보는 설치된 시스템의 /etc/hostname.if 파일과 관련 설정 파일에 기록된다. 각 인터페이스는 자신의 이름을 포함한 별도 파일을 사용한다.

기본 게이트웨이, DNS 해석과 호스트 이름도 설치 결과에 반영된다. DHCP를 계속 사용할 경우 부팅할 때마다 임대 정보를 받아 현재 네트워크 상태를 구성한다.

설치 파일 세트를 네트워크에서 내려받을 때에는 미러, 서버 경로와 전송 방식을 선택한다. HTTPS를 사용하면 전송 경로가 보호되며, 파일 세트 자체의 서명도 별도로 검증된다.

설치 프로그램은 네트워크 설정이 끝나면 이름 해석과 서버 접근을 시험한다. 연결에 실패할 경우 셸로 이동해 ifconfig, route, ping, dhcpleasectl과 DNS 조회 도구로 상태를 확인할 수 있다.

설치 후 영구 네트워크 설정은 hostname.if(5), resolv.conf(5), mygate(5) 또는 동적 네트워크 데몬의 설정을 통해 관리된다. 현대 OpenBSD에서는 DHCP와 라우터 광고 처리에 별도의 기본 데몬이 사용될 수 있다.

PF는 설치 과정에서 복잡한 규칙을 자동으로 만들지 않는다. 설치 후 시스템의 역할과 노출할 서비스에 맞춰 /etc/pf.conf를 구성하고 활성 상태를 확인해야 한다.

사용자 계정 구성

설치 프로그램은 root 계정의 암호를 설정하고 일반 사용자 계정을 하나 만들 수 있게 한다. root는 시스템 전체를 관리하는 특별한 계정이므로 일상적인 로그인보다 필요한 관리 작업에만 사용하는 것이 권장된다.

일반 사용자 이름은 소문자로 시작하고 허용된 문자 규칙을 따라야 한다. 설치 프로그램은 사용자 이름, 표시 이름과 암호를 입력받아 계정을 만든다.

설치 중 생성된 일반 사용자는 전통적으로 wheel 그룹에 추가된다. 이를 통해 관리자가 doas 정책이나 su 사용 권한을 해당 그룹 기준으로 구성할 수 있다.

wheel 그룹에 속한다는 것만으로 모든 root 권한을 자동으로 얻는 것은 아니다. doas를 사용하려면 /etc/doas.conf에 별도의 허용 규칙이 필요하다.

설치 프로그램에서 sshd를 활성화하면 root의 원격 SSH 로그인 허용 여부도 묻는다. 일반적으로는 root 직접 로그인을 제한하고 일반 사용자로 접속한 뒤 필요한 명령만 doas로 실행하는 구성이 더 안전하다.

사용자 계정에는 홈 디렉터리, 로그인 셸, 기본 그룹과 로그인 클래스가 연결된다. 설치 뒤에는 useradd, usermod, chpass, passwd와 그룹 관리 도구로 변경할 수 있다.

암호 외에도 OpenSSH 공개 키 인증을 구성할 수 있다. 사용자의 ~/.ssh/authorized_keys에 허용할 공개 키를 등록하고 파일과 디렉터리의 소유권·권한을 제한해야 한다.

서비스용 계정은 일반 사용자와 분리한다. 여러 기본 데몬과 패키지는 로그인할 수 없는 전용 사용자를 사용하여 파일 소유권과 프로세스 권한을 격리한다.

계정 데이터는 /etc/master.passwd, /etc/passwd와 관련 데이터베이스에 저장된다. 수동 편집보다 vipw와 계정 관리 명령을 사용해야 형식 검사와 데이터베이스 갱신이 함께 처리된다.

부트 과정

OpenBSD의 부트 과정은 펌웨어, 플랫폼별 부트 코드, OpenBSD 부트 로더, 커널, initrc 순서로 진행된다. 세부 단계와 파일 이름은 BIOS, UEFI와 하드웨어 아키텍처에 따라 달라질 수 있다.

전원이 켜지면 시스템 펌웨어가 초기 하드웨어 설정을 수행하고 부팅 가능한 장치를 선택한다. BIOS 시스템은 디스크의 부트 코드로, UEFI 시스템은 EFI 시스템 파티션의 OpenBSD 부트 프로그램으로 제어를 넘긴다.

초기 부트 코드는 파일 시스템을 읽을 수 있는 다음 단계 부트 로더를 불러온다. 플랫폼에 따라 이 과정은 여러 단계로 나뉘거나 펌웨어가 직접 부트 로더 파일을 실행할 수 있다.

OpenBSD 부트 로더는 기본적으로 /bsd 커널을 찾는다. 잠시 동안 boot> 프롬프트를 제공하여 다른 커널, 장치나 부트 옵션을 지정할 수 있다.[164]

일반 커널은 /bsd, 설치·복구용 램디스크 커널은 /bsd.rd에 위치한다. 이전 커널이나 대체 커널 이미지가 남아 있는 경우 문제가 발생했을 때 선택하여 시험할 수 있다.

boot -s는 커널을 단일 사용자 모드로 시작하게 한다. bsd.rd를 지정하면 설치 프로그램과 복구 셸이 포함된 램디스크 환경으로 부팅한다.

커널은 CPU, 메모리, 장치와 파일 시스템을 초기화하고 루트 파일 시스템을 마운트한다. 이후 첫 사용자 공간 프로세스로 /sbin/init을 PID 1로 실행한다.

init은 단일 사용자 모드가 아니면 /etc/rc를 실행한다. rc는 파일 시스템 검사와 마운트, 네트워크 설정, 임시 디렉터리 정리, 커널 변수와 시스템 데몬 시작을 처리한다.[165][166]

부팅이 완료되면 init/etc/ttys 설정에 따라 콘솔과 터미널에서 getty를 실행한다. 그래픽 로그인을 활성화한 경우 Xenodm과 관련 서비스도 rc 체계를 통해 시작된다.

시스템 시작과 종료

OpenBSD의 시작 과정은 init/etc/rc가 관리한다. /etc/rc.conf에는 기본 서비스 설정이 있고, 관리자의 변경은 주로 /etc/rc.conf.local에 기록된다.

서비스 활성화와 시작·중지는 rcctl을 통해 수행한다. rcctl enable은 다음 부팅부터 서비스를 활성화하고, start, stop, restart, reloadcheck는 실행 상태를 제어한다.

네트워크 초기화는 netstart/etc/hostname.if 파일을 중심으로 이루어진다. 인터페이스, 브리지, VLAN, 무선 연결과 기본 경로가 구성된 뒤 네트워크에 의존하는 데몬이 시작된다.

부팅 중 오류가 발생하면 시스템이 단일 사용자 모드로 들어갈 수 있다. 관리자는 콘솔 셸에서 파일 시스템과 설정을 수정한 뒤 exit 또는 Ctrl-D로 다중 사용자 부팅을 계속할 수 있다.

시스템 종료에는 shutdown, halt, rebootpoweroff를 사용한다. 이 명령들은 실행 중인 사용자에게 종료를 알리고 init에 상태 전환을 요청한다.[167]

종료 과정에서는 /etc/rc.shutdown과 서비스 종료 절차가 실행된다. 데몬에 종료 요청을 보내고 난수 시드와 필요한 상태를 저장하며, 파일 시스템의 변경 내용을 디스크에 동기화한다.[168]

reboot는 정상 종료 뒤 다시 부팅하고, halt는 시스템을 정지한다. poweroff는 지원되는 하드웨어에서 전원 차단까지 요청한다.

전원 버튼이나 가상 머신 관리 기능이 정상적인 ACPI 종료 신호를 전달하면 운영체제가 이를 받아 같은 종료 절차를 수행할 수 있다. 전원을 강제로 차단하면 쓰기 중이던 데이터와 파일 시스템 메타데이터가 손상될 수 있다.

서비스를 수동으로 강제 종료하거나 시스템 전원을 바로 끄는 대신 rc 체계와 정상 종료 명령을 사용하는 것이 중요하다. 특히 데이터베이스, 파일 서버와 암호화된 저장 장치는 종료 전 내부 상태를 안전하게 기록해야 한다.

설정 파일 관리

OpenBSD의 시스템 설정은 주로 /etc 아래의 텍스트 파일에 저장된다. 중앙의 단일 설정 데이터베이스보다 각 하위 시스템과 데몬이 문서화된 개별 파일을 읽는 구조를 사용한다.

네트워크 인터페이스는 /etc/hostname.if, PF는 /etc/pf.conf, OpenSSH 서버는 /etc/ssh/sshd_config, 서비스 활성화는 /etc/rc.conf.local에서 관리한다.

설정 파일의 형식은 같은 이름의 매뉴얼 5절에 문서화되는 경우가 많다. 설정을 바꾸기 전에 해당 매뉴얼에서 기본값, 문법, 권한과 재적재 방법을 확인할 수 있다.

기본 시스템이 제공하는 원본 설정 파일을 직접 크게 수정하기보다 로컬 전용 파일이 제공되는 경우 이를 사용한다. 예를 들어 rc 기본값은 /etc/rc.conf에 있지만 실제 변경은 rcctl/etc/rc.conf.local에 저장한다.

설정 변경 뒤에는 가능한 경우 문법 검사 기능을 사용한다. PF는 pfctl -n, SSH 서버는 sshd -t, 여러 데몬은 자체 검사 옵션을 제공한다.

서비스가 설정 재적재를 지원하면 rcctl reload로 중단 없이 새 설정을 읽게 할 수 있다. 지원하지 않거나 내부 상태가 크게 바뀌는 경우에는 서비스를 다시 시작해야 한다.

정식 릴리스 업그레이드에서는 새 기본 설정 파일과 관리자가 수정한 기존 파일 사이에 차이가 생긴다. sysmerge/etc와 일부 /var 파일을 비교하고 자동 병합하거나 사용자에게 충돌 처리를 요청한다.[169]

관리자가 변경한 설정과 비밀 키는 별도로 백업해야 한다. 기본 시스템 업그레이드와 패키지 데이터베이스만으로 로컬 정책과 서비스 데이터를 완전히 복원할 수는 없다.

설정 파일에는 암호, 개인 키, 무선 네트워크 키와 접근 토큰이 포함될 수 있다. 소유권과 권한을 제한하고 공개 저장소나 일반 사용자용 백업 위치에 그대로 저장하지 않아야 한다.

여러 시스템을 같은 정책으로 운영할 때에는 자동 설치 파일, siteXX.tgz, install.site, 구성 관리 도구나 자체 패키지를 사용할 수 있다. 다만 시스템별 호스트 키와 비밀 정보는 공통 이미지에 그대로 복제하지 않도록 구분해야 한다.

자동 설치

OpenBSD의 autoinstall은 설치 프로그램의 질문에 응답 파일을 이용해 자동으로 답하여 무인 설치 또는 업그레이드를 수행하는 기능이다.[170]

설치 환경의 시작 메뉴에서 Autoinstall을 선택할 수 있으며, 네트워크 부팅 환경에서는 일정 시간 동안 사용자가 개입하지 않으면 자동 설치가 시작되도록 구성할 수 있다.

응답 파일은 일반 설치 프로그램이 묻는 질문과 답을 순서대로 기록한다. 호스트 이름, 인터페이스, 디스크, 사용자, 파일 세트와 설치 서버 같은 항목을 자동화할 수 있다.

네트워크 자동 설치에서는 DHCP 정보로 응답 파일 서버와 이름을 찾고 HTTP를 통해 파일을 내려받는다. 일반 install.conf 외에도 MAC 주소나 호스트 이름별 파일을 제공하여 시스템마다 다른 설정을 적용할 수 있다.

업그레이드에는 대응하는 upgrade.conf 계열 응답 파일을 사용할 수 있다. 설치와 업그레이드는 질문 항목이 다를 수 있으므로 같은 응답 파일을 그대로 공유하지 않는다.

bsd.rd 내부에 /auto_install.conf 또는 /auto_upgrade.conf를 포함하면 네트워크에서 응답 파일을 받지 않고 로컬 파일을 사용하게 할 수 있다.

자동 설치 응답에는 디스크 초기화와 포맷을 포함할 수 있으므로 대상 장치 선택이 잘못되면 여러 시스템의 데이터가 자동으로 삭제될 수 있다. 장치 식별, MAC 주소와 호스트별 응답 파일을 신중하게 구성해야 한다.

공식 설치 파일 세트 외에 siteXX.tgz와 호스트별 site 파일 세트를 제공할 수 있다. 이를 통해 조직의 인증서, 기본 설정, 로컬 프로그램과 디렉터리 구조를 설치 과정에 추가할 수 있다.

설치 마지막에 /install.site, 업그레이드 마지막에 /upgrade.site가 존재하고 실행 가능하면 새 시스템을 chroot한 상태에서 실행된다. 패키지 설치 예약, 설정 생성과 첫 부팅 작업 등록에 사용할 수 있다.[171]

자동 설치는 단순히 디스크 이미지를 복제하는 방식과 달리 각 시스템에서 일반 설치 절차를 수행한다. 하드웨어 감지, 파일 시스템 생성, 호스트 키 생성과 설정 질문의 결과가 개별 시스템에 맞게 적용된다.

원격 관리

OpenBSD의 기본 원격 관리 수단은 OpenSSH다. 설치 중 sshd를 활성화하거나 설치 뒤 rcctl enable sshdrcctl start sshd로 서비스를 시작할 수 있다.

SSH 서버 설정은 /etc/ssh/sshd_config에서 관리한다. 수신 주소와 포트, 인증 방식, root 로그인, 사용자·그룹 제한과 전달 기능 등을 설정할 수 있다.[172]

설정을 변경한 뒤에는 sshd -t로 문법과 키 파일을 검사할 수 있다. 현재 원격 연결을 유지한 상태에서 새 설정을 검증한 뒤 재적재하면 잘못된 설정으로 관리 접속을 잃을 위험을 줄일 수 있다.

암호 인증보다 공개 키 인증을 사용할 수 있다. 사용자의 공개 키는 authorized_keys에 등록하고 개인 키는 관리자의 클라이언트 시스템에 보관한다.

서버의 호스트 키는 클라이언트가 접속 대상의 신원을 확인하는 데 사용한다. 호스트 키가 예고 없이 바뀌면 재설치나 정상적인 키 교체인지, 중간자 공격 가능성이 있는지 확인해야 한다.

root의 직접 SSH 로그인을 막고 일반 사용자 계정과 doas를 조합할 수 있다. 관리 권한을 특정 명령과 사용자에 한정하면 원격 계정 침해의 영향을 줄일 수 있다.

PF에서 SSH 접속을 허용할 주소와 인터페이스를 제한할 수 있다. 인터넷 전체에 관리 포트를 노출하는 대신 관리망, VPN 또는 특정 주소에서만 접근하도록 구성할 수 있다.

OpenSSH는 포트 전달과 터널 기능도 제공하지만, 편의를 위해 불필요한 전달 기능을 허용하면 내부 네트워크 접근 경로가 늘어날 수 있다. 서버의 용도에 맞춰 에이전트, TCP, X11과 터널 전달을 제한한다.

원격으로 시스템 업그레이드나 부트 설정을 변경할 때에는 실패 시 복구할 콘솔 경로가 있는지 고려해야 한다. 서버 관리 인터페이스, 직렬 콘솔, 가상 머신 콘솔 또는 현장 접근 없이 부트 실패가 발생하면 SSH만으로 복구할 수 없다.

시스템 로그, last, who, doas와 SSH 인증 기록을 통해 원격 접속과 관리 명령의 흔적을 확인할 수 있다. 로그 자체도 원격 공격자가 변경하지 못하도록 권한과 원격 전송 정책을 구성할 수 있다.

복구 환경

OpenBSD는 단일 사용자 모드와 bsd.rd 램디스크 환경을 주요 복구 수단으로 제공한다. 두 환경은 목적과 사용할 수 있는 도구가 다르다.

단일 사용자 모드는 설치된 커널과 루트 파일 시스템을 사용하지만 일반 서비스와 사용자 로그인을 시작하지 않는다. 부트 로더에서 boot -s를 지정하면 root 셸로 들어갈 수 있다.[173]

단일 사용자 모드의 루트 파일 시스템은 읽기 전용일 수 있으며 /usr와 다른 파티션도 아직 마운트되지 않을 수 있다. 파일 시스템 검사를 마친 뒤 필요한 파티션을 읽기·쓰기로 마운트해야 설정과 암호를 수정할 수 있다.

root 암호를 잊은 경우 물리적 콘솔에서 단일 사용자 모드로 부팅하고 루트와 /usr를 마운트한 뒤 passwd로 새 암호를 설정할 수 있다. 콘솔이 /etc/ttys에서 안전하지 않은 것으로 지정되면 단일 사용자 셸 전에 root 암호를 요구할 수 있다.[174]

일반 커널이나 루트 파일 시스템으로 정상 부팅할 수 없으면 설치 매체 또는 /bsd.rd로 부팅한다. 시작 메뉴에서 Shell을 선택하면 메모리 기반의 복구 셸에 들어간다.

bsd.rd는 설치된 디스크의 파일 시스템과 독립적으로 실행되므로 손상된 루트 파일 시스템을 검사하거나 마운트하고, 디스크레이블, 부트 로더와 네트워크 설정을 복구할 수 있다.[175]

복구 셸에서는 fsck, mount, disklabel, fdisk, bioctl, ifconfig, route와 파일 복사 도구 등 제한된 명령을 사용할 수 있다. 일반 설치의 모든 패키지와 셸 도구가 포함되는 것은 아니다.

파일 시스템 오류가 의심되면 해당 파일 시스템을 마운트하지 않은 상태에서 검사하는 것이 원칙이다. 사용 중인 파일 시스템에 강제 수정을 적용하면 손상이 확대될 수 있다.

부트 로더가 손상된 경우 설치 매체로 부팅하여 대상 파일 시스템을 마운트하고 플랫폼별 installboot 절차로 부트 코드를 다시 설치할 수 있다. 정확한 명령과 부트 파일은 아키텍처마다 다르다.

잘못된 /etc/fstab, 네트워크 설정이나 rc 설정 때문에 부팅이 실패하면 복구 환경에서 해당 파일을 수정하거나 문제가 되는 서비스를 비활성화할 수 있다.

암호화된 softraid 볼륨은 파일 시스템을 마운트하기 전에 bioctl로 해제해야 한다. 키나 암호문을 잃어버린 경우 복구 환경만으로 암호화 데이터를 우회할 수는 없다.

복구 환경은 백업을 대체하지 않는다. 저장 장치의 물리적 손상, 암호화 키 유실, 삭제된 데이터와 심각한 파일 시스템 손상에 대비하려면 시스템 설정과 사용자 데이터를 별도 장치나 원격 시스템에 백업해야 한다.

릴리스와 업데이트

OpenBSD의 릴리스 체계는 정식 릴리스, 개발이 계속되는 -current, 정식 릴리스에 중요한 수정 사항을 반영한 -stable, 그리고 -current를 주기적으로 빌드한 스냅샷으로 구분된다. 이들은 단순히 안정성 수준이 다른 같은 제품이 아니라 사용 목적과 업데이트 방식이 서로 다른 개발 계통이다.

일반적인 운영 환경에서는 정식 릴리스를 설치하고 syspatch로 기본 시스템의 오류와 보안 문제를 수정하며, pkg_add -u로 외부 패키지를 업데이트하는 방식이 권장된다. 다음 정식 릴리스가 공개되면 sysupgrade 또는 설치 램디스크를 이용해 바로 다음 버전으로 업그레이드한다.

-current는 다음 정식 릴리스가 만들어질 개발 소스 트리다. 새로운 기능, 인터페이스 변경과 코드 제거가 먼저 반영되므로 최신 개발에 참여하거나 변경 사항을 시험하려는 사용자에게 적합하다. 일반적인 장기 운영 서버에서 단순히 더 새로운 프로그램을 사용하기 위한 선택으로 보는 것은 적절하지 않다.

스냅샷은 특정 시점의 -current를 빌드한 설치 파일과 패키지다. -current 사용자는 소스 전체를 직접 컴파일하지 않고도 최신 개발 상태에 가까운 바이너리로 시스템을 갱신할 수 있다.

-stable은 정식 릴리스의 기능과 인터페이스를 유지하면서 중요한 오류와 보안 수정만 선별하여 반영하는 소스 브랜치다. 새로운 기능을 지속적으로 받아들이는 -current와는 목적이 다르며, 공식 errata 패치의 수정 내용도 -stable에 반영된다.

정식 릴리스

OpenBSD 정식 릴리스는 일정 시점의 개발 소스 트리를 안정화하고 시험한 뒤 버전 번호를 부여해 공개한 배포판이다. 릴리스 번호는 7.8, 7.9처럼 주번호와 부번호로 구성되지만, 일반적인 의미의 대규모 주버전과 소규모 부버전을 구분하지는 않는다.

2026년 5월 19일 공개된 OpenBSD 7.9는 프로젝트의 60번째 정식 릴리스다.[176]

정식 릴리스에는 플랫폼별 커널, 기본 시스템 파일 세트, 설치 이미지, 소스 코드, 포트 트리와 바이너리 패키지가 함께 제공된다. 각 구성 요소는 해당 릴리스의 커널과 라이브러리 인터페이스에 맞춰 빌드된다.

릴리스 파일 세트에는 baseXX.tgz, compXX.tgz, manXX.tgz와 Xenocara 관련 파일 등이 포함된다. 여기서 XX는 점을 제외한 릴리스 번호를 나타낸다.

정식 릴리스는 설치 이미지나 네트워크 미러를 통해 새로 설치할 수 있다. 바로 이전 릴리스가 설치되어 있다면 sysupgrade, bsd.rd 또는 수동 업그레이드 절차로 전환할 수 있다.

정식 릴리스가 공개된 뒤에도 심각한 오류나 보안 문제가 발견될 수 있다. 이러한 문제는 errata에 기록되며 소스 패치, -stable 반영과 지원되는 아키텍처의 syspatch 바이너리 패치로 수정된다.

정식 릴리스는 -current보다 인터페이스와 패키지 구성이 일정하게 유지된다. 새로운 기능을 수시로 추가하지 않고 필요한 오류 수정만 제공하므로 서버와 장기간 운영할 장치의 일반적인 기준점으로 사용된다.

정식 릴리스용 패키지는 해당 릴리스의 기본 시스템과 함께 사용해야 한다. 다른 릴리스나 -current 스냅샷의 패키지를 혼합하면 공유 라이브러리와 의존 관계가 일치하지 않을 수 있다.

릴리스 페이지에는 새 기능, 보안 개선, 드라이버 변경, 제거된 기능과 플랫폼별 변경 사항이 정리된다. 시스템을 새 버전으로 전환하기 전에 릴리스 정보와 별도의 업그레이드 안내서를 모두 확인해야 한다.

-current

-current는 OpenBSD의 주 개발 브랜치다. 개발자가 커밋한 새로운 기능, 오류 수정, 드라이버, 시스템 호출 변경과 코드 제거가 다음 정식 릴리스를 향해 지속적으로 반영된다.

정식 릴리스가 만들어지면 개발은 멈추지 않고 곧 다음 릴리스를 목표로 계속된다. 따라서 -current는 특정한 고정 버전이라기보다 시간에 따라 계속 변하는 OpenBSD 소스 트리의 현재 상태를 뜻한다.

새로운 기능과 보안 완화 기술은 대체로 -current에서 먼저 개발되고 시험된다. 충분한 안정화와 릴리스 준비 과정을 거친 뒤 다음 정식 릴리스에 포함된다.

-current에서는 시스템 호출, 라이브러리 인터페이스, 설정 파일과 패키지 의존성이 변경될 수 있다. 특정 날짜의 커널과 사용자 공간, 패키지를 서로 다른 시점의 것으로 혼합하면 정상적으로 실행되지 않을 수 있다.

-current 사용자는 프로젝트의 변경 사항과 Following -current 안내를 지속적으로 확인해야 한다. 일부 변경에는 설정 파일 수정, 서비스 재구성, 사용자 데이터 이전 또는 패키지 전체 업데이트가 필요하다.[177]

FAQ 본문은 최신 정식 릴리스를 기준으로 작성되므로 -current의 새 기능과 변경 사항이 아직 반영되지 않을 수 있다. -current 사용자는 매뉴얼 페이지, 변경 기록과 관련 메일링 리스트도 함께 참고해야 한다.[178]

-current는 정식 릴리스의 업데이트 채널이 아니다. 정식 릴리스를 유지하면서 보안 수정만 받으려는 사용자는 syspatch 또는 -stable을 사용해야 한다.

한번 -current로 전환한 시스템을 이전 정식 릴리스로 단순히 되돌리는 것은 지원되는 일반 절차가 아니다. 스냅샷 사이에서도 다운그레이드는 데이터 형식과 인터페이스 변화 때문에 실패할 수 있다.

-current를 사용하려면 최신 스냅샷을 설치하거나 정식 릴리스에서 sysupgrade -s로 전환할 수 있다. 소스에서 직접 빌드하려면 먼저 현재 소스와 가까운 바이너리 스냅샷을 설치해야 한다.

OpenBSD 공식 FAQ는 정식 릴리스 사이를 소스 빌드만으로 건너뛰지 말고, -current를 빌드하려면 최신 스냅샷을 기준으로 삼으라고 안내한다.[179]

-stable

-stable은 특정 정식 릴리스에서 분기하여 중요한 오류와 보안 수정만 반영하는 소스 브랜치다. 예를 들어 OpenBSD 7.9의 수정 브랜치는 일반적으로 OPENBSD_7_9와 같은 이름으로 관리된다.

-stable은 다음 릴리스의 새로운 기능을 가져오는 브랜치가 아니다. 정식 릴리스의 인터페이스와 동작을 가능한 한 유지하면서 운영에 필요한 수정만 적용한다.

공식 errata에 공개된 기본 시스템 패치는 -stable 소스 브랜치에도 반영된다. 소스에서 커널과 사용자 공간을 직접 빌드하는 사용자는 이 브랜치를 추적하여 수정된 시스템을 만들 수 있다.

-stable은 별도의 완전한 바이너리 설치판을 의미하지 않는다. 기본적인 바이너리 수정은 정식 릴리스에 syspatch를 적용하는 방식으로 제공되며, -stable이라는 이름은 주로 소스 브랜치를 가리킨다.

-stable을 소스에서 빌드하려면 먼저 대응하는 정식 릴리스 바이너리가 설치되어 있어야 한다. 다른 오래된 릴리스에서 최신 -stable 소스를 바로 빌드하여 업그레이드하는 방식은 지원되지 않는다.

포트 트리에도 -stable 계통이 존재한다. 기본 시스템과 달리 포트의 -stable은 최신 정식 릴리스에 대해 심각한 보안 문제와 주요 오류의 수정 패키지를 제공하는 데 집중한다.[180]

정식 릴리스 사용자가 반드시 소스를 내려받아 -stable을 직접 빌드해야 하는 것은 아니다. 지원되는 아키텍처에서는 syspatch가 같은 중요한 수정의 바이너리 형태를 제공하므로 일반 사용자에게 더 단순하다.

-stable은 새로운 하드웨어 드라이버나 기능이 필요한 사용자에게 적합한 계통이 아니다. 그러한 변경은 일반적으로 -current와 다음 정식 릴리스에서 제공된다.

스냅샷

OpenBSD 스냅샷은 -current 소스 트리의 특정 시점을 자동 또는 주기적으로 빌드한 바이너리 배포물이다. 플랫폼별 커널과 설치 파일 세트, 설치 이미지와 대응하는 패키지가 미러의 snapshots 영역에 제공된다.

스냅샷은 정식 릴리스처럼 장기간 고정된 버전이 아니다. 새 스냅샷이 올라오면 이전 파일과 패키지가 교체될 수 있으며, 미러 사이의 동기화 시점에도 차이가 생길 수 있다.

스냅샷의 목적은 개발 중인 변경을 더 많은 하드웨어와 사용 환경에서 시험하는 것이다. 사용자는 소스 전체를 직접 빌드하지 않고도 최신 드라이버와 기능을 시험하고 문제를 보고할 수 있다.

스냅샷이라고 해서 항상 모든 기능이 안정적으로 동작한다고 보장되지는 않는다. 특정 시점에는 인터페이스 전환, 라이브러리 변경이나 일시적인 빌드 문제가 포함될 수 있다.

스냅샷으로 시스템을 갱신할 때에는 기본 시스템과 패키지를 서로 가까운 시점의 것으로 맞춰야 한다. 기본 시스템만 갱신하고 오래된 스냅샷 패키지를 유지하면 공유 라이브러리와 의존성 불일치가 생길 수 있다.

sysupgrade -s는 현재 시스템을 새 스냅샷으로 업그레이드하는 데 사용한다. 필요한 파일을 내려받아 검증하고, 다음 부팅에서 자동 업그레이드하도록 /bsd.upgrade를 준비한다.[181]

스냅샷 패키지는 pkg_add가 시스템 상태를 확인하여 미러의 snapshots/packages 경로에서 찾을 수 있다. -current 또는 베타 커널에서는 패키지 경로의 버전 변수가 스냅샷 영역으로 확장된다.[182]

정식 릴리스 직전의 베타 기간에는 스냅샷이 다음 릴리스 후보에 가까워지지만, 정식 릴리스와 동일하다고 볼 수는 없다. 최종 릴리스 과정에서 추가 수정과 파일 재빌드가 이루어질 수 있다.

릴리스 주기

OpenBSD는 대체로 약 6개월마다 새로운 정식 릴리스를 발표한다. 프로젝트가 밝히는 목표 시기는 매년 5월과 11월이다.[183]

릴리스가 공개된 직후에는 다음 버전의 기능 개발이 -current에서 계속된다. 개발 기간 동안 새로운 기능과 구조 변경이 반영되고 스냅샷을 통해 반복적으로 빌드·시험된다.

릴리스 시점이 가까워지면 대규모 기능 변경을 줄이고 오류 수정, 설치 시험, 문서 갱신과 플랫폼별 빌드에 집중한다. 정식 릴리스용 소스와 포트 브랜치가 만들어지고 파일 세트와 패키지가 준비된다.

규칙적인 릴리스 주기는 변경 사항을 오랫동안 미완성 상태로 쌓아두기보다 일정한 간격으로 통합하고 정리하도록 한다. 새 기능은 해당 릴리스에 준비되지 않았다면 다음 개발 주기로 넘어갈 수 있다.

OpenBSD의 버전 번호는 이러한 반년 주기에 맞춰 순차적으로 증가한다. 버전 번호만으로 호환성 규모나 지원 기간을 판단하기보다 개별 릴리스 정보와 업그레이드 안내를 확인해야 한다.

릴리스 날짜는 개발 상황과 준비 상태에 따라 달라질 수 있으므로 정확히 6개월마다 같은 날짜에 공개된다는 의미는 아니다. 공식 FAQ는 이를 약 6개월 간격의 목표 일정으로 설명한다.

업그레이드

OpenBSD의 릴리스 업그레이드는 설치된 기본 시스템을 바로 다음 정식 릴리스로 전환하는 과정이다. 새 설치와 달리 사용자 데이터와 대부분의 로컬 설정을 유지하면서 커널, 기본 파일 세트와 시스템 구성을 갱신한다.

공식 업그레이드 안내는 한 정식 릴리스에서 바로 다음 릴리스로 이동하는 경우만 지원한다. 여러 버전을 한 번에 건너뛰려면 중간 릴리스를 순서대로 거쳐야 한다.[184]

예를 들어 7.7에서 7.9로 직접 업그레이드하기보다 먼저 7.8로 올리고 필요한 절차를 완료한 뒤 7.9로 전환해야 한다.

업그레이드 전에는 대상 릴리스의 안내서를 읽고 제거된 기능, 설정 문법, 라이브러리, 사용자·그룹과 파일 시스템 변경을 확인해야 한다. 단순히 새 파일 세트를 덮어쓰는 것만으로 모든 전환 작업이 끝나지 않을 수 있다.

중요하거나 물리적으로 멀리 떨어진 시스템은 동일하거나 유사한 로컬 장비에서 먼저 업그레이드를 시험하는 것이 권장된다. 부트 실패나 네트워크 설정 오류가 생기면 원격 접속만으로 복구하기 어려울 수 있다.

업그레이드 전에는 시스템 설정, 사용자 데이터, 서비스 데이터베이스와 암호화 키를 백업해야 한다. RAID와 스냅샷은 잘못된 업그레이드나 관리 실수에 대한 독립적인 백업을 대신하지 않는다.

기본 시스템을 업그레이드한 뒤에는 새 버전에서 더 이상 필요하지 않은 오래된 파일을 제거하고 설정을 병합해야 할 수 있다. sysmerge와 릴리스별 안내가 이 과정을 지원한다.

외부 패키지는 기본 시스템 업그레이드와 별도로 갱신해야 한다. 새 릴리스로 부팅한 뒤 해당 릴리스용 저장소에서 pkg_add -u를 실행하여 패키지와 의존성을 교체한다.

업그레이드 중에는 기존 커널과 일부 백업 파일이 남을 수 있다. 새 시스템이 정상적으로 부팅되고 서비스와 데이터가 확인된 뒤에만 불필요한 과거 파일을 정리해야 한다.

sysupgrade

sysupgrade는 OpenBSD를 다음 정식 릴리스 또는 새로운 스냅샷으로 자동 업그레이드하는 기본 시스템 관리 도구다. OpenBSD 6.6에서 처음 도입되었다.[185]

기본 실행에서는 /etc/installurl에 설정된 미러에서 다음 정식 릴리스의 커널과 파일 세트를 내려받는다. -s 옵션을 사용하면 다음 릴리스 대신 -current 스냅샷을 선택한다.

내려받은 파일은 기본적으로 /home/_sysupgrade에 저장된다. sysupgradesignify를 이용하여 설치 파일의 서명을 검증한다.

검증이 끝나면 램디스크 커널을 /bsd.upgrade에 배치한다. 기본 동작에서는 시스템을 재부팅하고, 부트 로더가 /bsd.upgrade를 자동으로 선택하여 일회성 무인 업그레이드를 시작한다.

업그레이드 환경은 /home/_sysupgrade의 파일 세트와 자동 응답 파일을 이용해 기존 시스템을 갱신한다. 과정이 끝나면 일반 커널로 다시 부팅한다.

sysupgrade -n은 파일을 내려받아 검증하고 /bsd.upgrade를 준비하지만 즉시 재부팅하지 않는다. 관리자가 유지보수 시점을 따로 정해야 할 때 사용할 수 있다.

-k는 업그레이드가 끝난 뒤 내려받은 파일을 유지하고, -b는 다운로드 기본 디렉터리를 변경한다. 파티션 공간이 부족한 시스템에서는 다른 파일 시스템을 선택할 수 있다.

-R은 특정 정식 릴리스 버전을 지정한다. 다만 공식 매뉴얼도 한 버전에서 바로 다음 버전으로 이동하는 경우만 시험되었다고 밝히며, 버전 건너뛰기와 다운그레이드는 신뢰할 수 있는 절차가 아니다.

sysupgrade/usr에 과거 릴리스의 불필요한 파일이 계속 쌓이는 문제를 완전히 해결하지 않는다. 공간이 부족하면 업그레이드를 중단하며, 관리자가 오래된 파일을 직접 정리하거나 심한 경우 재설치해야 할 수 있다.

sysupgrade가 자동화하는 것은 기본 파일 세트 전환이다. 릴리스별 설정 변경, 외부 패키지 갱신, 서비스 데이터 이전과 최종 동작 검증은 여전히 관리자가 수행해야 한다.

syspatch

syspatch는 정식 OpenBSD 릴리스의 기본 시스템에 제공되는 바이너리 패치를 내려받아 검증하고 설치하거나 되돌리는 도구다.[186]

옵션 없이 실행하면 설치되지 않은 모든 누적 패치를 적용한다. 특정 패치만 임의로 골라 적용하는 방식이 아니라 현재 릴리스에 필요한 패치 집합을 순서대로 설치한다.

패치를 적용하기 전에는 교체할 파일의 롤백 아카이브를 /var/syspatch 아래에 만든다. 이후 서명된 패치 파일의 내용을 검증하고 대상 파일을 교체한다.

syspatch -c는 설치 가능한 패치를 표시하며 cron 같은 자동 검사에서 사용할 수 있다. -l은 현재 설치된 패치 목록을 보여준다.

-r은 가장 최근에 설치한 패치를 되돌리고, -R은 설치된 패치 전체의 롤백을 시도한다. 롤백이 가능하다고 해서 운영 중인 서비스와 데이터 상태까지 자동으로 과거로 되돌아가는 것은 아니다.

syspatch는 공식 정식 릴리스에서만 사용하도록 설계되어 있다. -current 스냅샷이나 소스로 빌드한 -stable 시스템을 위한 일반 업데이트 도구가 아니다.

OpenBSD 7.9에서는 amd64, i386과 arm64에 완전한 바이너리 패치를 제공하고, 다른 아키텍처에는 기계 독립적인 수정이 존재하는 경우에만 패치가 제공된다.[187]

패치가 커널을 변경하면 재부팅해야 새 커널이 실행된다. 라이브러리나 데몬이 변경된 경우에도 해당 프로세스를 다시 시작하지 않으면 기존 메모리에 적재된 코드가 계속 실행될 수 있다.

syspatch는 외부 패키지를 수정하지 않는다. 브라우저, 데이터베이스와 패키지로 설치한 서버 프로그램은 pkg_add -u를 통해 별도로 갱신해야 한다.

패키지 업데이트

OpenBSD의 외부 패키지는 pkg_add -u로 업데이트한다. 패키지 이름을 지정하지 않으면 설치된 모든 패키지와 의존성을 현재 저장소의 적합한 버전으로 갱신한다.[188]

정식 릴리스 시스템에서는 /etc/installurl을 바탕으로 해당 릴리스와 아키텍처의 패키지 경로를 사용한다. 기본 패키지 경로 외에 packages-stable 저장소도 검색할 수 있다.

정식 릴리스용 갱신 패키지는 제3자 소프트웨어의 보안 문제나 주요 오류를 수정하기 위해 제공된다. 기본 시스템의 syspatch와 외부 소프트웨어의 패키지 업데이트를 모두 수행해야 전체 시스템이 수정된 상태가 된다.

운영체제를 다음 릴리스로 업그레이드한 뒤에는 pkg_add -u를 실행하여 패키지를 새 릴리스용으로 전환한다. 오래된 릴리스용 패키지를 그대로 유지하면 공유 라이브러리와 런타임 인터페이스가 맞지 않을 수 있다.

-current 스냅샷에서는 기본 시스템과 패키지의 빌드 시점을 가깝게 유지해야 한다. 스냅샷 미러는 계속 갱신되므로 오래된 기본 시스템에서 최신 패키지만 설치하는 방식은 실패할 수 있다.

패키지 업데이트는 의존 패키지를 먼저 갱신하고, 충돌과 필요한 공유 라이브러리를 확인한 뒤 관련 패키지를 하나의 업데이트 집합으로 처리한다.

새 버전의 설정 예제와 설치 후 안내가 제공될 수 있다. 패키지 파일 교체가 성공했더라도 서비스의 설정 형식과 데이터베이스를 별도로 이전해야 할 수 있다.

업데이트된 실행 파일은 이미 실행 중인 프로세스에 자동으로 반영되지 않는다. 네트워크 데몬과 장기간 실행되는 응용 프로그램은 업데이트 뒤 재시작해야 한다.

오류 수정과 보안 권고

OpenBSD는 정식 릴리스에서 발견된 중요한 오류와 보안 문제를 릴리스별 errata 페이지에 공개한다. 각 항목에는 영향을 받는 구성 요소, 문제 설명, 패치와 적용 지침이 포함된다.[189]

기본 시스템의 소스 패치는 unified diff 형식으로 제공되며 signify 서명으로 보호된다. 사용자는 패치를 검증하고 소스 트리에 적용한 뒤 수정된 구성 요소를 빌드할 수 있다.

지원되는 아키텍처에서는 같은 수정이 syspatch 바이너리 형태로 제공된다. 소스를 직접 빌드하지 않아도 서명된 수정 파일을 설치할 수 있다.

보안 관련 수정은 문제를 숨기는 방식보다 원인과 수정 내용을 공개하는 전체 공개 원칙을 따른다. 사용자는 공개된 변경 내용을 검토하고 자신이 사용하는 구성에 미치는 영향을 판단할 수 있다.[190]

모든 프로그램 오류가 정식 errata로 제공되는 것은 아니다. 영향이 작거나 다음 릴리스에서만 수정되는 문제도 있으며, -current에는 정식 릴리스용 패치보다 먼저 변경이 반영될 수 있다.

외부 패키지의 보안 문제는 기본 시스템 errata와 별도로 처리된다. 최신 릴리스의 -stable 포트 브랜치와 갱신된 바이너리 패키지를 통해 중요한 수정이 제공될 수 있다.

관리자는 errata 페이지, syspatch -c, 패키지 업데이트와 프로젝트 공지를 함께 확인해야 한다. 한 채널만 확인하면 기본 시스템 또는 외부 프로그램의 수정이 누락될 수 있다.

지원 정책

OpenBSD는 정식 릴리스가 공개된 뒤 일정 기간 동안 중요한 오류와 보안 수정 사항을 제공한다. OpenBSD 7.9 errata는 지원되는 릴리스의 -stable 브랜치를 릴리스 후 1년 동안 유지한다고 명시한다.[191]

약 6개월마다 새 릴리스가 공개되므로 일반적으로 현재 릴리스와 바로 이전 릴리스가 일정 기간 겹쳐 지원되는 구조가 된다. 다만 실제 지원 여부는 해당 릴리스의 errata와 패치 브랜치 상태를 기준으로 확인해야 한다.

지원 기간이 끝난 릴리스는 새 보안 패치와 오류 수정이 제공되지 않는다. 오래된 릴리스를 계속 사용하는 것은 기본 시스템과 패키지 모두 알려진 문제에 노출될 가능성을 높인다.

OpenBSD는 여러 정식 릴리스를 한 번에 건너뛰는 업그레이드를 지원하지 않는다. 오래된 시스템은 각 중간 릴리스를 순서대로 거치거나, 백업 뒤 최신 릴리스를 새로 설치하고 데이터를 이전하는 방식을 선택해야 한다.

모든 아키텍처가 동일한 형태의 바이너리 패치를 받는 것은 아니다. 완전한 syspatch 지원 아키텍처와 기계 독립적인 패치만 제공되는 아키텍처가 구분될 수 있다.

하드웨어 플랫폼 자체의 지원도 영구적이지 않다. 개발자와 시험 장비 부족, 컴파일러 지원, 유지 비용과 보안 기능 구현 가능성에 따라 다음 릴리스에서 특정 아키텍처가 제외될 수 있다.

정식 릴리스 지원은 외부 패키지의 모든 업스트림 버전을 장기간 유지한다는 의미가 아니다. 패키지 수정 범위와 제공 여부는 포트 팀의 작업, 업스트림 지원과 빌드 가능성에 따라 달라진다.

장기간 운영해야 하는 시스템도 지원 종료 시점 전에 다음 릴리스로 전환하는 계획이 필요하다. 특히 원격 장비와 네트워크 기반 시설은 콘솔 접근, 설정 호환성, 패키지 변경과 복구 절차를 미리 시험해야 한다.

OpenBSD의 지원 정책은 수년 동안 하나의 정식 릴리스를 고정하는 장기 지원판 방식보다, 비교적 짧고 규칙적인 릴리스 주기를 따라 시스템 전체를 지속적으로 다음 버전으로 이동시키는 모델에 가깝다.

지원 플랫폼

OpenBSD는 특정 프로세서 계열 하나에 집중하지 않고 여러 하드웨어 아키텍처에서 동작하는 다중 플랫폼 운영체제로 개발된다. 2026년 공개된 OpenBSD 7.9는 alpha, amd64, arm64, armv7, hppa, i386, landisk, luna88k, macppc, octeon, powerpc64, riscv64, sparc64를 공식 지원한다.[192]

OpenBSD에서 공식 지원 플랫폼이라는 표현은 단순히 커널이 한 번 부팅된 적이 있다는 의미가 아니다. 해당 플랫폼용 정식 릴리스와 설치 매체가 제공되고, 시스템이 자신의 기본 시스템을 자체적으로 컴파일할 수 있으며, 대부분의 기본 명령과 개발 도구가 동작하고 정기적으로 스냅샷을 만들려는 유지보수 체계가 존재해야 한다.

그러나 같은 공식 지원 플랫폼 안에서도 실제 하드웨어 지원 범위는 다르다. amd64처럼 다양한 개인용 컴퓨터와 서버에서 사용할 수 있는 플랫폼이 있는 반면, powerpc64처럼 일부 시스템과 보드에 집중하는 플랫폼도 있다. 프로세서 아키텍처가 지원된다고 해서 그 아키텍처를 사용하는 모든 컴퓨터, 시스템 온 칩과 주변 장치가 자동으로 지원되는 것은 아니다.

플랫폼 지원은 커널의 프로세서·메모리 관리 코드뿐 아니라 부트 로더, 설치 환경, 컴파일러, 시스템 라이브러리, 장치 드라이버와 패키지 빌드 환경이 함께 갖춰져야 완성된다. OpenBSD는 여러 아키텍처에서 같은 소스 코드를 빌드하고 실행함으로써 코드에 숨어 있는 바이트 순서, 정렬, 자료형 크기와 메모리 모델에 대한 잘못된 가정을 발견하기도 한다.

amd64

amd64는 AMD64 또는 x86-64 명령어 집합을 사용하는 64비트 개인용 컴퓨터와 서버를 위한 OpenBSD 플랫폼이다. AMD가 처음 설계한 64비트 x86 확장을 기반으로 하며, Intel 64를 구현한 인텔 프로세서에서도 동작한다.

현대 OpenBSD에서 amd64는 가장 널리 사용되고 시험되는 플랫폼 가운데 하나다. 일반 데스크톱과 노트북, 랙 서버, 소형 네트워크 장비, 클라우드와 가상 머신 환경에서 사용할 수 있다.

BIOS와 UEFI 부팅을 모두 지원한다. UEFI 시스템에서는 EFI 시스템 파티션의 부트 로더를 통해 커널을 불러올 수 있으며, OpenBSD 7.9에서는 EFI 시스템 파티션에 있는 커널과 bsd.rd 파일을 직접 불러오는 기능도 추가되었다.[193]

프로세서의 다중 코어와 대칭형 다중 처리, 가상 메모리, NX 비트, IOMMU, 하드웨어 난수와 여러 보안 기능을 활용한다. 커널과 사용자 공간은 주소 공간 무작위화, W^X, 위치 독립 실행 파일과 지원되는 제어 흐름 보호를 적용한다.

저장 장치에서는 SATA·AHCI, NVMe, USB 대용량 저장 장치, SCSI와 여러 RAID 컨트롤러를 지원한다. 네트워크 장치는 인텔, 브로드컴, 리얼텍과 여러 서버용 이더넷 컨트롤러가 지원되지만 제품별 칩셋과 개정에 따라 차이가 있다.

그래픽 장치는 인텔과 AMD 계열을 중심으로 커널 모드 설정과 Xenocara 환경을 지원한다. NVIDIA의 최신 독점 GPU는 공개 문서와 자유 드라이버 부족으로 지원 범위가 제한되며, 모든 노트북의 하이브리드 그래픽과 전원 관리가 완전하게 동작하는 것은 아니다.

노트북에서는 ACPI, 배터리, 화면 밝기, 절전과 재개 기능을 지원하지만 펌웨어 구현과 하드웨어 조합에 따라 차이가 크다. 같은 프로세서를 사용하더라도 무선 장치, 터치패드와 절전 상태가 지원 여부를 좌우할 수 있다.

amd64vmm·vmd 기반 가상화의 호스트 플랫폼으로 사용할 수 있다. QEMU, VMware, Hyper-V와 여러 하이퍼바이저의 게스트로도 실행할 수 있으며, VirtIO 장치를 사용하면 가상 디스크와 네트워크를 효율적으로 연결할 수 있다.

OpenBSD 7.9의 완전한 syspatch 바이너리 업데이트가 제공되는 플랫폼 가운데 하나이기도 하다. 따라서 일반적인 서버와 데스크톱에서는 소스를 직접 다시 빌드하지 않고도 기본 시스템의 보안·신뢰성 패치를 적용할 수 있다.[194]

amd64라는 플랫폼 이름이 모든 64비트 PC 하드웨어의 완전한 지원을 뜻하지는 않는다. 최신 장치의 공개 문서, 펌웨어 재배포 조건과 개발 장비의 उपलब्ध 여부에 따라 일부 기능은 지원되지 않거나 후속 릴리스에서 추가될 수 있다.[195]

arm64

arm64는 AArch64 실행 상태를 사용하는 64비트 ARM 시스템을 위한 플랫폼이다. 단일한 PC 규격보다 여러 시스템 온 칩과 서버·개발 보드·노트북을 포괄하므로, 실제 지원은 프로세서 명령어 집합뿐 아니라 각 SoC와 보드의 펌웨어·장치 구성을 기준으로 결정된다.

현재 대상에는 Allwinner A64·H5·H6·H616, Amlogic G12B·SM1, AMD Opteron A1100, Ampere eMAG·Altra, Marvell ARMADA, 여러 Rockchip SoC, Raspberry Pi 3·4·5, 일부 Qualcomm Snapdragon과 Socionext 계열이 포함된다.[196]

Apple Silicon에서는 M1과 M2 계열의 여러 Mac이 지원된다. Apple 하드웨어는 일반 PC와 다른 부트·장치 구조를 사용하므로 Asahi Linux 프로젝트를 비롯한 공개 역공학 자료와 OpenBSD 자체 드라이버 작업을 바탕으로 지원이 발전해 왔다.

Apple Silicon 지원에는 CPU, 저장 장치, USB, 일부 그래픽 출력, 키보드·트랙패드와 네트워크 장치가 포함될 수 있지만 모델과 세대에 따라 차이가 있다. 최신 M3 이후 계열이 공식 페이지의 현재 지원 대상으로 명시되어 있지는 않으므로 M1·M2 지원을 모든 Apple Silicon 기기로 일반화해서는 안 된다.

Raspberry Pi 3·4·5도 arm64 플랫폼에 포함된다. Raspberry Pi는 ARM 코어를 시작하기 위해 GPU 측 부트 펌웨어를 필요로 하며, 설치 매체에는 부팅에 필요한 재배포 가능한 파일이 포함된다.

ARM 서버에서는 Ampere Altra와 eMAG, AMD Opteron A1100과 일부 Marvell 기반 시스템을 지원한다. UEFI와 ACPI를 사용하는 서버는 보드별 장치 트리를 사용하는 임베디드 시스템보다 PC·서버에 가까운 부팅·장치 탐색 환경을 제공할 수 있다.

임베디드 보드는 일반적으로 U-Boot와 Flattened Device Tree를 사용한다. 부트 로더가 커널, 메모리 정보와 장치 트리를 전달하고 OpenBSD 커널은 이를 바탕으로 SoC 내부 장치를 인식한다.

arm64는 다중 코어와 SMP를 지원하며, 플랫폼에 따라 GIC 인터럽트 컨트롤러, SMMU IOMMU, PCI Express, NVMe, USB와 여러 이더넷·무선 장치를 사용할 수 있다.

같은 SoC를 사용한 보드라도 전원 관리 장치, 저장 장치 배선, 이더넷 PHY와 펌웨어가 다를 수 있다. 따라서 공식적으로 SoC가 지원된다는 사실만으로 임의의 보드가 완전하게 작동한다고 판단할 수 없다.

arm64amd64, i386과 함께 OpenBSD 7.9에서 완전한 syspatch 바이너리 업데이트가 제공되는 플랫폼이다.[197]

armv7

armv7은 32비트 ARMv7 아키텍처 기반 시스템 온 칩과 개발 보드를 위한 플랫폼이다. 주 대상은 Allwinner A10·A20·A33·A80·H2+·H3·R16·R40·V40, NXP i.MX6·i.MX7과 TI OMAP4·AM335x 계열이다.

대표적인 지원 장치에는 BeagleBone과 BeagleBone Black, PandaBoard, Cubieboard, Banana Pi 일부 모델, Orange Pi 일부 모델, SABRE Lite, Nitrogen6X, Wandboard, CuBox-i와 Novena가 있다.[198]

armv7은 여러 제조사의 SoC를 하나의 플랫폼 아래에서 지원하지만 내부적으로는 sunxi, imx, am335x, panda처럼 하드웨어 계통을 구분한다. 각 계통은 부트 방식, 인터럽트 컨트롤러, 타이머, 저장 장치와 네트워크 장치가 다르다.

이 플랫폼은 자체 시스템을 자체 컴파일할 수 있는 self-hosting 상태다. 다만 공식 플랫폼 페이지에 따르면 SMP는 지원하지 않으므로 다중 코어 SoC에서도 커널이 하나의 CPU만 사용할 수 있다.

네트워크 지원도 SoC별로 다르다. AM335x, i.MX, PandaBoard와 일부 Allwinner 계열에서는 내장 이더넷이나 USB 이더넷을 사용할 수 있지만, 모든 보드의 네트워크 인터페이스가 지원되는 것은 아니다.

저장 장치는 SD·MMC, 일부 SATA·AHCI와 USB 저장 장치를 사용할 수 있다. 보드에 따라 내장 eMMC와 microSD의 장치 인식 순서와 부트 매체가 달라진다.

많은 ARMv7 개발 보드에는 배터리로 유지되는 실시간 시계가 없거나 기본 보드에 장착되지 않는다. 이 경우 부팅 직후 시각이 정확하지 않을 수 있으며 네트워크가 연결되면 ntpd를 통해 보정한다.

armv7은 저전력 장치와 오래된 임베디드 보드에서 사용할 수 있지만 32비트 주소 공간과 제한된 메모리, 낮은 연산 성능 때문에 현대적인 대형 패키지와 데스크톱 프로그램을 실행하는 데 제약이 있다.

64비트 ARM 하드웨어와 소프트웨어 생태계가 확대되면서 새로운 ARM 시스템 지원의 중심은 arm64로 이동하고 있다. 그러나 기존 ARMv7 장치의 활용과 이식성 검증을 위해 armv7은 OpenBSD 7.9에서도 공식 지원된다.

i386

i386은 IA-32 또는 32비트 x86 호환 개인용 컴퓨터를 위한 플랫폼이다. OpenBSD 프로젝트가 시작될 때부터 존재했으며 표준 PC와 여러 구형 노트북·서버에서 실행할 수 있다.

이름은 인텔 80386에서 유래하지만 실제로는 이후의 다양한 32비트 x86 프로세서를 지원한다. 다만 현대 OpenBSD를 실행하는 데 필요한 프로세서 기능과 메모리 요구 사항 때문에 초기 386 시스템 자체에서 최신 릴리스를 실용적으로 사용하는 것과는 차이가 있다.

BIOS 기반 PC와 여러 전통적인 버스·주변 장치를 지원하며 CD, USB 디스크, 네트워크와 과거에는 플로피 이미지도 설치 수단으로 제공되어 왔다.

OpenBSD의 초기 PC 하드웨어 지원과 많은 장치 드라이버는 i386에서 발전했다. 이후 64비트 시스템이 보편화되면서 일반적인 새 설치의 중심은 amd64로 이동하였다.

i386은 32비트 주소 공간 때문에 개별 프로세스와 커널이 사용할 수 있는 메모리 범위가 제한된다. 대용량 메모리와 현대적인 서버·브라우저·컴파일 작업에서는 amd64보다 불리하다.

일부 최신 보안 완화 기능은 프로세서 기능과 주소 공간의 제약으로 amd64와 같은 수준으로 구현하기 어렵다. 또한 새로운 하드웨어 제조사는 32비트 운영체제를 고려하지 않는 경우가 많다.

OpenBSD 공식 플랫폼 페이지는 amd64 사용 증가와 32비트 PC 하드웨어의 노후화를 이유로 i386에는 적용하기 쉬운 수정과 중요한 보안 수정만 역이식한다고 설명한다.[199]

그럼에도 i386은 OpenBSD 7.9의 공식 지원 플랫폼이며 정식 설치 파일과 스냅샷이 제공된다. amd64, arm64와 함께 완전한 syspatch 바이너리 업데이트 대상에도 포함된다.

i386의 유지에는 오래된 32비트 프로그램을 실행하는 목적뿐 아니라 x86 코드의 자료형 크기와 주소 공간 가정을 검사하고, 64비트에서 드러나지 않는 오류를 찾는 의미도 있다.

powerpc64

powerpc64는 64비트 IBM POWER 계열 시스템을 위한 OpenBSD 플랫폼이다. OpenBSD 6.8에서 처음 공식 릴리스되었다.

현재 핵심 지원 대상은 POWER9 프로세서를 사용하는 PowerNV 시스템이다. Raptor Computing Systems의 Talos II와 Blackbird가 대표적인 지원 장비다.[200]

PowerNV는 IBM POWER 하드웨어를 비교적 개방된 펌웨어와 운영체제 환경에서 직접 실행하는 플랫폼이다. OpenBSD는 petitboot와 OPAL 펌웨어를 통해 부팅하고 하드웨어 서비스를 사용한다.

POWER8 코드도 포함되어 있지만 공식 플랫폼 설명에서는 시험되지 않은 상태로 언급된다. POWER 프로세서를 사용한다고 해서 모든 IBM 서버에서 동작하는 것은 아니다.

특히 PowerVM이나 PowerKVM 같은 하이퍼바이저 아래에서는 현재 OpenBSD/powerpc64가 동작하지 않는다. 따라서 지원되는 PowerNV 실기와 일반적인 IBM 가상 LPAR 환경을 구분해야 한다.

설치는 USB 미니루트 이미지나 HTTP·TFTP를 통한 네트워크 부팅으로 수행할 수 있다. petitboot 메뉴에서 OpenBSD 설치 환경을 선택하는 방식이 사용된다.

지원 장치에는 POWER9 시스템의 PCI Express, NVMe, USB, SATA와 일부 네트워크 컨트롤러가 포함된다. 그러나 x86 서버에 비해 시험 가능한 장비와 개발자 수가 적어 장치별 지원 범위가 좁을 수 있다.

powerpc64는 빅 엔디언 또는 플랫폼 고유 메모리 모델과 정렬 특성을 통해 공통 커널과 사용자 공간 코드의 이식성 오류를 발견하는 데에도 의미가 있다.

riscv64

riscv64는 64비트 RISC-V 명령어 집합을 사용하는 시스템을 위한 OpenBSD 플랫폼이다. RISC-V는 개방형 명령어 집합이지만 실제 보드의 부트 펌웨어, 인터럽트, 타이머, PCIe와 주변 장치 구성은 제조사마다 다르다.

현재 주요 대상은 SiFive HiFive Unmatched이며, Allwinner D1 기반 Mango Pi MQ-Pro와 Nezha, StarFive VisionFive·VisionFive 2, Microchip PolarFire SoC Icicle Kit도 지원 목록에 포함된다.[201]

PolarFire SoC Icicle Kit 지원은 공식 페이지에서 불완전한 상태로 설명된다. 지원 목록에 포함되더라도 모든 장치와 기능이 같은 수준으로 동작하는 것은 아니다.

부팅에는 보드 펌웨어, OpenSBI와 U-Boot 같은 여러 초기 단계가 사용될 수 있다. 펌웨어가 하드웨어를 초기화하고 OpenBSD 부트 로더 또는 커널로 제어를 전달한다.

HiFive Unmatched에서는 USB에 미니루트 이미지를 기록하고 보드와 함께 제공된 microSD의 부트 환경을 통해 설치 프로그램을 시작할 수 있다.

지원되는 저장 장치에는 HiFive Unmatched와 VisionFive 2의 NVMe, VisionFive 계열의 SD·MMC가 포함된다. 이더넷과 USB 지원도 보드·컨트롤러별 드라이버에 따라 달라진다.

RISC-V 규격은 선택 가능한 확장이 많으므로 riscv64라는 이름만으로 모든 64비트 RISC-V 프로세서가 호환되는 것은 아니다. OpenBSD가 요구하는 기본 ISA와 페이지 기반 가상 메모리, 타이머·인터럽트·펌웨어 인터페이스를 갖춰야 한다.

RISC-V 이식은 초기에는 QEMU와 교차 컴파일 도구를 활용하여 커널 부팅과 기본 사용자 공간을 개발하는 방식으로 진행되었다. 이후 실제 하드웨어와 자체 빌드 환경을 갖추면서 공식 플랫폼으로 발전하였다.[202]

개방형 명령어 집합은 CPU 명세 접근에는 유리하지만, 보드에 탑재된 GPU, 무선 장치와 주변 컨트롤러까지 자동으로 공개되는 것은 아니다. 실제 장치 지원은 각 제조사의 문서와 개발 작업에 달려 있다.

기타 플랫폼

OpenBSD 7.9는 주요 범용 플랫폼 외에도 여러 역사적 워크스테이션과 특수 시스템 아키텍처를 공식 지원한다.

alpha는 Digital Equipment Corporation의 64비트 Alpha 프로세서 기반 시스템을 지원한다. 과거 고성능 워크스테이션과 서버에 사용된 아키텍처로, 리틀 엔디언 64비트 환경에서 OpenBSD의 이식성을 시험하는 역할도 한다.

hppa는 Hewlett-Packard PA-RISC 워크스테이션과 서버를 위한 플랫폼이다. 여러 32비트 HP 9000 시스템과 일부 64비트 모델을 32비트 모드로 지원한다.[203]

landisk는 SH4 프로세서를 사용하는 IO-DATA LANDISK 계열 소형 저장 장치를 지원한다. 한정된 메모리와 임베디드 하드웨어를 대상으로 하는 플랫폼이다.

luna88k는 Motorola 88000 계열 프로세서를 사용한 Omron LUNA-88K와 LUNA-88K2 워크스테이션을 지원한다. 현재는 매우 희귀한 하드웨어지만 OpenBSD의 88k 아키텍처 코드와 역사적 시스템 지원을 유지한다.

macppc는 New World ROM을 사용하는 PowerPC 기반 Apple Macintosh를 지원한다. iMac, Power Mac, iBook과 PowerBook 일부 모델이 대상이며, Intel Mac이나 Apple Silicon Mac은 각각 amd64arm64에 해당한다.

octeon은 Cavium Octeon MIPS64 시스템을 위한 플랫폼이다. 일부 네트워크 장비와 개발 보드를 지원하며, MIPS의 빅 엔디언 실행 환경과 SoC 장치 구조를 사용한다.

sparc64는 Sun UltraSPARC와 Fujitsu SPARC64 워크스테이션·서버를 지원한다. OpenFirmware를 통해 부팅하며 일부 다중 프로세서 시스템과 서버용 장치를 사용할 수 있다.

과거에는 VAX, Amiga, SGI, 68k Macintosh, Sharp Zaurus, Sun3와 여러 MIPS·PowerPC·ARM 시스템도 지원되었다. 그러나 유지할 개발자와 작동하는 장비 부족, 컴파일러 문제, 커널 변화와 보안 기능 구현 비용 때문에 중단되었다.

OpenBSD는 플랫폼을 단순히 목록에 남겨두기보다 정식 설치와 자체 빌드가 가능한 상태를 공식 지원 기준으로 삼는다. 이 기준을 더 이상 충족하기 어려운 플랫폼은 후속 릴리스에서 제거될 수 있다.[204]

플랫폼 이식 과정

새 플랫폼으로 OpenBSD를 이식하려면 CPU 명령어 집합용 컴파일러만 준비하는 것으로는 충분하지 않다. 부트 과정, 예외와 인터럽트, 가상 메모리, 시스템 호출, 문맥 전환, 타이머, 콘솔과 기본 저장 장치가 모두 구현되어야 한다.

초기 단계에서는 기존 시스템에서 대상 아키텍처용 교차 컴파일러와 바이너리 도구를 만든다. 이를 이용해 커널과 최소 사용자 공간을 빌드하고 에뮬레이터나 실제 하드웨어에서 실행한다.

부트 코드 또는 기존 펌웨어가 커널을 메모리에 적재하고 필요한 하드웨어 정보를 전달해야 한다. 플랫폼에 따라 UEFI, OpenFirmware, U-Boot, OpenSBI, petitboot 또는 전용 펌웨어 인터페이스를 사용한다.

커널의 기계 의존 계층에는 초기 CPU 설정, 페이지 테이블, 캐시, TLB, 예외 벡터, 인터럽트와 문맥 전환 코드가 포함된다. 공통 UVM과 프로세스 관리 코드가 사용할 수 있도록 아키텍처별 인터페이스를 구현해야 한다.

초기 콘솔 드라이버가 동작하면 부팅 메시지와 디버거 출력을 확인할 수 있다. 이후 타이머와 인터럽트 컨트롤러, 루트 파일 시스템에 접근할 저장 장치와 네트워크 장치를 순서대로 지원한다.

사용자 공간을 실행하려면 시스템 호출 규약, ELF 실행 파일 형식, 런타임 링커, C 라이브러리와 스레드 지원이 대상 아키텍처에 맞게 동작해야 한다.

초기 개발에서는 다른 플랫폼에서 교차 컴파일하지만, 공식 지원 단계에 도달하려면 대상 시스템이 자신의 커널과 기본 사용자 공간을 직접 빌드할 수 있는 self-hosting 상태가 중요하다.

정식 릴리스에는 설치 램디스크, 부트 로더, 파일 세트와 설치 문서가 필요하다. 일반 커널만 부팅되는 상태와 사용자가 실제로 설치·업그레이드할 수 있는 공식 플랫폼 사이에는 큰 차이가 있다.

포트의 유지에는 지속적인 빌드와 실기 시험도 필요하다. 공통 커널 변경이 특정 아키텍처의 정렬, 원자 연산, 캐시 또는 바이트 순서에서 문제를 일으킬 수 있으므로 릴리스마다 전체 시스템을 다시 검증해야 한다.

이식 과정은 공통 코드의 품질을 높이기도 한다. 하나의 아키텍처에서 우연히 작동한 자료형 크기, 포인터와 정수 변환, 메모리 정렬과 엔디언 가정이 다른 플랫폼에서 오류로 드러날 수 있다.

장치 드라이버 지원

OpenBSD의 장치 드라이버 지원은 프로세서 아키텍처 지원과 별도로 평가해야 한다. 운영체제가 CPU에서 부팅되더라도 저장 장치, 네트워크, 그래픽, 오디오와 전원 관리 장치에 대응하는 드라이버가 없으면 실제 사용 범위가 제한된다.

드라이버는 커널 소스 트리에 포함되어 공개적으로 개발된다. OpenBSD는 소스 코드가 없는 바이너리 전용 커널 드라이버를 적재하는 방식을 제공하지 않는다.

PCI, USB, ACPI, FDT와 여러 플랫폼 버스는 장치를 탐색하고 해당 드라이버를 부착한다. 드라이버의 매뉴얼 페이지에는 지원되는 칩셋, 필요한 펌웨어, 알려진 제한과 진단 메시지가 기록된다.

한 제품 계열 안에서도 제조사가 칩셋을 변경할 수 있으므로 제품명만으로 지원 여부를 판단하기 어렵다. PCI·USB 식별자와 실제 장치 칩셋을 드라이버 매뉴얼의 지원 목록과 비교해야 한다.

OpenBSD는 다른 BSD나 Linux의 공개 드라이버에서 장치 동작에 관한 지식을 참고할 수 있지만, 코드를 그대로 사용할 수 있는지는 라이선스와 커널 인터페이스에 따라 다르다. 필요한 경우 OpenBSD 구조에 맞는 드라이버를 새로 작성하거나 재설계한다.

하드웨어 제조사가 공개 데이터시트를 제공하면 드라이버 개발과 유지가 쉬워진다. 반대로 레지스터 명세와 초기화 순서가 비공개이고 계약상 비밀 유지가 요구되면 OpenBSD의 공개 개발 방식과 충돌한다.

그래픽과 무선 장치는 드라이버뿐 아니라 대형 펌웨어가 필요한 경우가 많다. 커널 드라이버가 공개되어 있어도 장치 내부에서 실행되는 펌웨어의 배포 조건 때문에 설치 직후 기능을 사용할 수 없을 수 있다.

새로운 장치 지원은 주로 -current에 먼저 포함되고 스냅샷을 통해 시험된다. 정식 릴리스 계통에는 보안·중요 오류 수정과 달리 대규모 새 드라이버가 일반적으로 역이식되지 않는다.

지원하던 장치도 코드 유지가 불가능하거나 실제 시험 장비가 사라지면 제거될 수 있다. 드라이버가 컴파일된다는 사실만으로 실제 장치에서 안정적으로 동작한다고 보기는 어렵다.

펌웨어 정책

OpenBSD는 커널에서 실행되는 장치 드라이버와 장치 내부 프로세서에서 실행되는 펌웨어를 구분한다. 드라이버는 OpenBSD 소스 트리에 공개되어야 하지만, 일부 하드웨어 펌웨어는 소스 코드가 공개되지 않은 바이너리 형태로 제공될 수 있다.

재배포 조건이 OpenBSD의 배포 정책에 맞는 펌웨어는 설치 매체나 기본 시스템에 포함될 수 있다. 라이선스는 자유로운 수정까지 허용하지 않더라도 OpenBSD가 사용자에게 파일을 재배포할 수 있어야 한다.

재배포가 허용되지 않거나 별도 조건이 붙은 펌웨어는 OpenBSD 설치 파일에 직접 포함하지 않는다. 이러한 파일은 설치 후 fw_update를 사용하여 별도의 펌웨어 서버에서 받을 수 있다.[205]

fw_update는 현재 시스템에서 감지된 장치 드라이버를 확인하고 필요한 펌웨어를 자동으로 설치하거나 갱신한다. 일반적으로 설치 또는 업그레이드 후 인터넷 연결이 가능하면 자동으로 실행될 수 있다.

펌웨어 패키지는 일반 응용 프로그램 패키지와 별도의 서명 키와 저장소를 사용할 수 있다. OpenBSD 7.9 릴리스에도 기본 시스템, 패키지, syspatch와 구분된 펌웨어용 공개 키가 제공된다.[206]

무선 네트워크 장치가 펌웨어를 필요로 하지만 설치 환경에서 네트워크 연결 수단이 해당 무선 장치뿐이라면 순환 문제가 생길 수 있다. 이 경우 다른 컴퓨터에서 필요한 펌웨어 파일을 받아 이동식 매체로 전달하거나 유선 네트워크를 일시적으로 사용할 수 있다.[207]

펌웨어를 허용한다고 해서 바이너리 전용 커널 드라이버를 허용하는 것은 아니다. 펌웨어는 장치 내부의 제한된 프로세서에서 실행되고, 공개된 OpenBSD 드라이버가 커널과 장치 사이의 인터페이스를 관리한다.

다만 장치 펌웨어도 DMA와 공유 메모리를 통해 시스템에 영향을 줄 수 있으므로 완전히 신뢰 경계 밖에 있다고 볼 수는 없다. 지원되는 플랫폼에서는 IOMMU와 bus_dma 계층이 장치의 메모리 접근 범위를 제한하는 데 활용될 수 있다.

OpenBSD는 펌웨어를 필요악으로 무조건 포함하거나 모든 바이너리 펌웨어를 일률적으로 거부하지 않는다. 재배포 권한, 실제 하드웨어 사용 가능성, 드라이버의 공개성, 보안과 유지보수 가능성을 구분하여 처리한다.

이 정책은 일부 장치를 설치 직후 사용할 수 없게 만들 수 있지만, 운영체제 배포물이 법적·기술적으로 검토 가능한 상태를 유지하고 커널의 권한 있는 코드가 비공개 바이너리에 의존하지 않도록 한다.

가상화

OpenBSD는 amd64 호스트에서 하드웨어 지원 가상화를 이용하는 자체 하이퍼바이저 체계를 기본 시스템에 포함한다. 커널의 vmm, 사용자 공간 관리 데몬인 vmd, 제어 명령인 vmctl과 설정 파일 /etc/vm.conf가 함께 가상 머신의 생성과 실행을 담당한다.

vmmvmd는 데스크톱용 범용 가상화 제품보다 작고 단순한 서버 지향 구조를 따른다. 가상 머신은 직렬 콘솔과 가상 디스크, VirtIO 네트워크 장치를 중심으로 구성되며, OpenBSD와 Linux 게스트를 실행하는 용도에 집중한다.

현재 자체 가상화 환경은 그래픽 출력, 게스트 다중 프로세서, 장치 직접 할당, 호스트 사이의 실시간 마이그레이션과 실행 중 하드웨어 변경을 제공하지 않는다. 따라서 그래픽 데스크톱 가상 머신이나 대규모 클라우드 하이퍼바이저를 완전히 대체하기보다, 네트워크 서비스 격리, 개발·시험, 소형 서버 통합과 자동 설치 환경에 적합하다.[208]

OpenBSD는 자체 하이퍼바이저의 호스트로 동작할 뿐 아니라 KVM·QEMU, VMware, Hyper-V, Xen, bhyve와 VirtualBox 같은 다른 가상화 환경의 게스트로도 실행할 수 있다. 이때 VirtIO와 하이퍼바이저별 반가상화 드라이버를 이용하면 완전히 에뮬레이션된 장치보다 효율적으로 디스크와 네트워크를 사용할 수 있다.

vmm

vmm은 OpenBSD 커널에 포함된 가상 머신 모니터 장치다. 사용자 공간의 vmd가 요청한 가상 CPU와 게스트 메모리를 만들고, 게스트가 실행될 때 프로세서의 하드웨어 가상화 기능을 제어한다.

현재 vmm 호스트 기능은 amd64 플랫폼에서 제공된다. 인텔 프로세서에서는 VMX와 EPT, AMD 프로세서에서는 SVM과 RVI에 해당하는 하드웨어 기능이 필요하다.[209]

EPT와 RVI는 게스트의 가상 주소에서 호스트의 물리 메모리까지 이어지는 두 단계 주소 변환을 프로세서가 지원하는 기능이다. OpenBSD FAQ에서는 이를 nested paging 또는 second-level address translation으로 설명한다.

프로세서 지원 여부는 부팅 메시지에서 확인할 수 있다. 인텔 시스템은 VMX/EPT, AMD 시스템은 SVM/RVI와 관련된 기능 표시가 나타나야 한다. 펌웨어 설정에서 가상화 기능이 비활성화되어 있으면 지원 프로세서에서도 vmm을 사용할 수 없다.[210]

OpenBSD 7.8부터 인텔 호스트에서는 unrestricted guest 기능이 요구된다. 오래된 인텔 프로세서는 VMX와 EPT를 일부 지원하더라도 현재 vmm의 호스트 요구 사항을 충족하지 못할 수 있다.[211]

게스트 메모리는 커널의 UVM 객체를 기반으로 관리된다. 각 가상 머신에는 지정된 최대 메모리 범위가 할당되며, 게스트의 물리 주소는 vmm과 하드웨어 가상화 기능을 통해 호스트 메모리에 대응된다.

게스트가 특권 명령, 입출력 포트 접근, 일부 인터럽트 제어 또는 가상화가 필요한 동작을 수행하면 프로세서가 게스트 실행을 중단하고 호스트의 vmm으로 제어를 넘긴다. 이를 VM exit라고 하며, 커널과 vmd가 원인을 처리한 뒤 게스트 실행을 재개한다.

모든 장치를 커널이 직접 구현하는 것은 아니다. CPU 실행과 메모리·인터럽트의 핵심 부분은 vmm이 처리하고, 가상 디스크와 네트워크 같은 장치 에뮬레이션의 상당 부분은 사용자 공간의 vmd 프로세스가 담당한다.

장치 에뮬레이션을 사용자 공간에 배치하면 복잡한 디스크 형식과 네트워크 입력 처리 코드를 커널에서 분리할 수 있다. 다만 게스트가 제공하는 장치 요청은 신뢰할 수 없는 입력이므로 vmd의 프로세스 격리와 입력 검증이 중요하다.

OpenBSD는 vmm을 적재식 외부 모듈로 제공하지 않는다. 지원되는 amd64 GENERIC 커널에 기능이 포함되며, 사용자 공간에서는 /dev/vmm 장치를 통해 vmd가 접근한다.

AMD 프로세서에서는 지원되는 하드웨어에서 Secure Encrypted Virtualization을 사용할 수 있다. SEV는 게스트 메모리를 암호화하고, SEV-ES는 게스트 레지스터 상태까지 보호 범위를 확장한다. OpenBSD 7.8에서는 vmm·vmd에서 SEV-ES 게스트를 시작하는 기능이 추가되었다.[212]

이러한 기밀 가상화 기능은 일반 가상 머신 격리를 대체하지 않는다. 지원되는 AMD 프로세서와 플랫폼 보안 프로세서, 펌웨어와 올바른 설정이 필요하며, 가상 디스크와 네트워크 데이터의 저장·전송 보호는 별도로 구성해야 한다.

vmd

vmd는 가상 머신의 실행과 장치 에뮬레이션을 담당하는 사용자 공간 데몬이다. 부팅 시 rcctl enable vmd로 활성화하고 rcctl start vmd로 시작할 수 있다.[213]

vmd는 커널의 vmm과 통신하여 가상 머신을 생성하고 게스트 CPU 실행을 제어한다. 관리자의 vmctl 요청을 받아 가상 머신 시작·중지, 상태 조회, 콘솔 연결, 일시 정지와 디스크 이미지 생성 등의 작업을 수행한다.

실행 중인 각 가상 머신에는 별도의 vmd 하위 프로세스와 가상 CPU 실행 스레드가 만들어진다. 특정 게스트의 장치 처리와 실행 상태를 다른 게스트와 분리하여 하나의 가상 머신에서 발생한 오류가 관리 데몬 전체로 확산되는 범위를 줄인다.

vmd 자체도 권한 분리 구조를 사용한다. 높은 권한이 필요한 제어 기능, 가상 머신 실행, 네트워크와 장치 처리를 여러 프로세스로 나누고 제한된 메시지 인터페이스로 연결한다.

가상 머신마다 소유 사용자와 그룹을 지정할 수 있다. 지정된 소유자는 해당 가상 머신을 시작·중지하고, 일시 정지하거나 콘솔을 열 수 있지만 다른 가상 머신을 자동으로 관리할 권한까지 얻는 것은 아니다.[214]

가상 머신의 장치 에뮬레이션은 하이퍼바이저의 주요 공격 표면이다. 악의적이거나 침해된 게스트는 비정상적인 디스크·네트워크 요청을 만들어 호스트의 장치 에뮬레이터를 공격할 수 있으므로, OpenBSD는 관련 프로세스를 분리하고 메시지와 장치 입력을 검증하는 방향으로 vmd를 개선해 왔다.

호스트가 정상 종료될 때 vmd는 실행 중인 게스트에 종료 요청을 보낼 수 있다. OpenBSD 게스트에서는 vmmci 장치가 이 요청을 받아 init에 전달하므로 게스트가 파일 시스템과 서비스를 정상적으로 종료할 수 있다.[215]

게스트가 vmmci나 이에 대응하는 종료 처리 기능을 지원하지 않으면 호스트의 요청이 정상 종료로 이어지지 않을 수 있다. 중요한 서비스는 게스트 운영체제 내부의 종료 동작과 파일 시스템 상태를 함께 확인해야 한다.

가상 머신 구성

가상 머신은 vmctl 명령의 인수로 일회성 구성하거나 /etc/vm.conf에 영구적으로 정의할 수 있다. vm.conf는 전역 설정, 가상 머신 정의와 가상 스위치 정의로 나뉜다.[216]

각 가상 머신에는 이름, 메모리 크기, 디스크 이미지, 네트워크 인터페이스와 부팅 매체를 지정한다. 필요에 따라 소유 사용자·그룹, 자동 시작, 부트 장치와 보안 관련 옵션도 설정할 수 있다.

가상 머신 이름은 vmctl에서 숫자 ID 대신 사용할 수 있다. 실행 중에는 각 가상 머신에 별도의 ID와 프로세스, 직렬 콘솔 장치가 할당된다.

enable로 표시한 가상 머신은 vmd가 시작되거나 설정을 읽을 때 자동 실행 대상으로 처리할 수 있다. 자동으로 시작하지 않을 가상 머신도 설정 파일에 정의한 뒤 vmctl start로 필요할 때 실행할 수 있다.

메모리 크기는 바이트 단위 또는 M, G 같은 사람이 읽기 쉬운 단위를 사용해 지정한다. 실행 중인 가상 머신의 메모리 크기를 동적으로 변경하는 기능은 제공되지 않으므로 변경 뒤에는 게스트를 다시 시작해야 한다.

현재 OpenBSD 자체 하이퍼바이저는 게스트 SMP를 지원하지 않는다. 호스트가 여러 CPU 코어를 사용하더라도 개별 게스트 운영체제에는 하나의 가상 CPU만 제공된다.[217]

게스트의 화면은 VGA나 가상 GPU가 아니라 직렬 콘솔을 중심으로 한다. 따라서 게스트 운영체제가 직렬 콘솔에서 설치와 부팅, 로그인을 지원해야 한다.

OpenBSD 설치 이미지는 직렬 콘솔 환경에서 사용할 수 있다. Linux 게스트는 배포판의 부트 로더와 커널 명령줄, getty 설정에서 가상 직렬 콘솔을 활성화해야 할 수 있다.

vmctl console은 실행 중인 가상 머신의 직렬 콘솔에 연결한다. 콘솔 연결을 종료하는 기본 이스케이프는 ~.이며, SSH 세션 안에서 연결했다면 SSH의 이스케이프 처리와 충돌하지 않도록 추가 이스케이프가 필요할 수 있다.

vmctl show는 실행 중인 가상 머신의 ID, 프로세스, 가상 CPU 수, 메모리, 콘솔, 소유자와 이름을 표시한다. start, stop, pause, unpause, consolewait 등의 명령으로 실행 상태를 관리한다.[218]

설정 파일의 일부 속성은 vmctl reload로 다시 읽을 수 있지만 메모리와 디스크 구성처럼 실행 중 변경할 수 없는 항목도 있다. 이러한 변경에는 가상 머신의 종료와 재시작이 필요하다.

현재 지원되는 자체 하이퍼바이저의 게스트 운영체제는 OpenBSD와 Linux로 제한된다. Windows나 다른 운영체제가 일부 조건에서 부팅할 가능성과 공식적으로 지원되는 게스트라는 표현은 구분해야 한다.[219]

가상 네트워크

vmd 가상 머신의 네트워크 장치는 VirtIO 네트워크 인터페이스로 제공되며, OpenBSD 게스트에서는 vio 드라이버로 인식된다. 호스트 쪽에는 tap 인터페이스가 만들어져 게스트의 가상 이더넷 프레임을 OpenBSD 네트워크 스택과 연결한다.[220]

가상 네트워크는 로컬 NAT, 브리지 연결, 격리된 가상 스위치와 직접 구성한 tap 인터페이스 등 여러 방식으로 만들 수 있다.

local interface 구성은 호스트와 게스트 사이에 사설 주소 범위를 자동으로 배정하고 간단한 DHCP·BOOTP 서비스를 제공한다. 호스트는 게스트의 게이트웨이 역할을 하며 PF의 주소 변환을 통해 외부 네트워크에 연결할 수 있다.[221]

이 방식은 소수의 시험용 가상 머신을 빠르게 연결하기 쉽지만, 자동으로 만들어지는 주소 범위와 PF 규칙이 기존 네트워크 정책과 충돌하지 않는지 확인해야 한다.

브리지 방식에서는 가상 머신의 tap 인터페이스와 호스트의 물리 인터페이스를 bridge에 함께 넣는다. 게스트는 물리 LAN에 직접 연결된 별도 컴퓨터처럼 주소를 받을 수 있다.

무선 인터페이스는 일반적인 이더넷 브리지와 동작 방식이 다를 수 있으므로 유선 인터페이스와 같은 구성을 그대로 적용할 수 없는 경우가 있다. 이러한 환경에서는 호스트가 라우터와 NAT 역할을 하는 구성이 더 단순할 수 있다.

가상 스위치는 여러 가상 머신의 인터페이스를 하나의 논리적 네트워크로 묶는다. 외부 물리 인터페이스에 연결하지 않으면 게스트끼리만 통신하는 격리된 네트워크를 만들 수 있다.

가상 스위치에는 이름을 붙이고 vm.conf에서 여러 가상 머신을 같은 스위치에 연결할 수 있다. 필요하면 호스트의 vether, bridge, VLAN과 PF를 결합하여 게스트 네트워크의 라우팅과 필터링을 구성한다.

routing domain을 이용하면 가상 머신 네트워크를 호스트의 기본 라우팅 테이블과 분리할 수 있다. 고객별 네트워크, 시험 환경과 관리망을 서로 다른 경로와 PF 정책으로 나누는 데 활용할 수 있다.

게스트가 외부 네트워크와 통신하려면 주소 배정뿐 아니라 호스트의 IP forwarding, 라우팅과 PF 규칙이 맞아야 한다. tap 인터페이스가 생성되었다는 사실만으로 인터넷 접근이 자동으로 제공되는 것은 아니다.

가상 머신 사이의 통신도 호스트의 PF 정책으로 제한할 수 있다. 서비스별 포트, 출발지 네트워크와 방향을 명시하여 같은 가상 스위치에 연결된 게스트가 서로 무제한 접근하지 못하게 구성할 수 있다.

네트워크 성능은 VirtIO 장치, 호스트의 물리 인터페이스, PF 규칙, CPU와 게스트 처리량에 영향을 받는다. 자체 가상화는 대규모 가상 스위치 오프로딩이나 장치 직접 할당을 제공하지 않으므로 높은 처리량이 필요한 환경에서는 실제 요구 사항을 시험해야 한다.

가상 디스크

vmd는 가상 머신의 저장 장치로 일반 파일 기반 디스크 이미지를 사용한다. 지원 형식에는 raw, qcow2와 qcow2 기반 이미지가 포함된다.[222]

raw 이미지는 파일의 위치가 게스트 디스크 블록에 직접 대응하는 단순한 형식이다. 구조가 간단하고 추가적인 형식 처리 비용이 적지만, 희소 파일을 사용하지 않으면 가상 디스크의 전체 크기만큼 호스트 저장 공간을 차지한다.

qcow2는 실제로 사용한 블록을 중심으로 공간을 할당할 수 있는 복사 시 기록 계열 형식이다. 같은 논리 크기의 가상 디스크라도 초기 파일 크기를 작게 유지할 수 있다.

vmctl create는 지정된 크기의 디스크 이미지를 생성한다. 현재 형식과 옵션에 따라 raw 또는 qcow2 이미지를 만들 수 있으며, 생성한 파일을 가상 머신의 disk 항목에 연결한다.[223]

설치 ISO나 bsd.rd와 같은 읽기 전용 부팅 매체도 가상 머신에 연결할 수 있다. 처음에는 설치 매체로 부팅하여 가상 디스크에 운영체제를 설치하고, 이후 부팅 순서에서 가상 디스크를 사용한다.

게스트에는 디스크가 VirtIO 블록 장치로 제공된다. OpenBSD 게스트에서는 vioblk가 장치를 인식하고 SCSI 디스크 계층을 통해 일반 sd 장치처럼 노출한다.

게스트 운영체제는 가상 디스크 안에 자체 파티션, 디스크레이블과 파일 시스템을 구성한다. 호스트에서 보이는 이미지 파일과 게스트 내부의 파일 시스템은 서로 다른 계층이다.

가상 디스크 파일의 소유권과 권한은 해당 가상 머신의 실행 계정이 읽고 쓸 수 있도록 설정해야 한다. 다른 일반 사용자나 불필요한 서비스가 디스크 이미지를 읽을 수 있으면 게스트 내부의 파일 권한과 관계없이 데이터가 노출될 수 있다.

게스트가 실행 중인 상태에서 디스크 이미지 파일을 일반 파일 복사로 백업하면 서로 다른 시점의 데이터와 메타데이터가 섞일 수 있다. 일관된 백업을 위해 게스트의 파일 시스템을 동기화하고 서비스를 정지하거나 가상 머신을 일시 정지·종료해야 한다.

현재 FAQ에서 말하는 가상 머신 스냅샷은 지원되지 않는다. 메모리 덤프와 복원 기능 또는 qcow2의 복사 시 기록 특성을 완전한 관리형 스냅샷 체계와 혼동해서는 안 된다.[224]

가상 디스크의 크기를 늘리더라도 게스트 내부의 파티션과 파일 시스템이 자동으로 확장되지는 않는다. 이미지 크기, 게스트 파티션과 파일 시스템을 각 계층에 맞는 도구로 순서대로 확장해야 한다.

중요한 가상 머신의 디스크 이미지는 호스트 파일 시스템 백업과 별도로 관리할 수 있다. RAID는 호스트 디스크 장애에 대한 가용성을 높이지만 게스트 내부 삭제, 파일 시스템 손상과 이미지 파일 훼손을 복구하는 백업은 아니다.

다른 하이퍼바이저의 게스트로 실행

OpenBSD는 자체 vmm의 게스트뿐 아니라 여러 외부 하이퍼바이저의 게스트 운영체제로 실행할 수 있다. 일반적으로 에뮬레이션된 PC 장치와 함께 VirtIO 또는 하이퍼바이저별 반가상화 장치를 사용한다.

VirtIO 드라이버는 KVM, QEMU, bhyve, VirtualBox와 OpenBSD vmm이 제공하는 가상 네트워크, 디스크, 콘솔, 메모리 벌루닝, 난수와 SCSI 장치를 지원한다.[225]

VirtIO 네트워크는 vio, 블록 디스크는 vioblk, 콘솔은 viocon, GPU는 viogpu, 메모리 벌루닝은 viomb, 난수 장치는 viornd, SCSI 어댑터는 vioscsi로 처리된다.

QEMU와 KVM에서는 가능한 경우 VirtIO 디스크와 네트워크를 선택하면 완전히 에뮬레이션된 IDE 디스크와 구형 네트워크 카드보다 오버헤드를 줄일 수 있다. 다만 설치 초기부터 게스트 커널이 해당 VirtIO 장치를 지원해야 한다.

VMware 환경에서는 vmx가 VMXNET3 네트워크 장치를 지원한다. vmt는 VMware Tools의 일부 기능을 커널에서 구현하여 호스트의 종료·재부팅 요청, 일시 정지·재개 통지, 호스트 시각과 게스트 정보 교환을 처리한다.[226][227]

Hyper-V에서는 hyperv 드라이버가 VMBus와 하이퍼콜 환경을 초기화하고 반가상화 디스크·네트워크 장치를 연결한다. 호스트와의 키·값 정보 교환도 지원된다.[228]

Hyper-V 지원 범위는 가상 머신 세대와 호스트 버전에 따라 다를 수 있다. 현재 매뉴얼은 Generation 2 가상 머신을 지원하지 않는다는 제한을 명시하므로, 설치 전에 사용하는 OpenBSD 릴리스의 최신 드라이버 문서를 확인해야 한다.

Xen 환경에서는 HVM 게스트 초기화와 XenStore, 반가상화 인터럽트·디스크·네트워크를 위한 드라이버가 제공된다. 실제 사용 가능성은 Xen 버전, 가상 머신 방식과 OpenBSD 플랫폼에 따라 달라진다.

VirtualBox에서는 에뮬레이션된 장치 또는 VirtIO 장치를 사용할 수 있다. VirtualBox Guest Additions 전체와 같은 통합 기능이 기본적으로 제공된다고 가정해서는 안 되며, OpenBSD가 지원하는 개별 가상 장치와 콘솔을 기준으로 구성해야 한다.

클라우드 환경도 내부적으로 KVM, Xen, Hyper-V 또는 다른 하이퍼바이저를 사용할 수 있다. OpenBSD 이미지가 공식적으로 제공되는지, 직렬 콘솔과 네트워크 장치가 지원되는지, 설치 이미지 직접 부팅과 사용자 데이터 주입이 가능한지를 서비스별로 확인해야 한다.

외부 하이퍼바이저에서 OpenBSD를 실행할 때에도 일반 하드웨어와 마찬가지로 커널, 기본 시스템과 패키지를 정상적으로 업데이트해야 한다. 하이퍼바이저가 제공하는 격리는 게스트 운영체제 내부의 보안 패치를 대신하지 않는다.

가상화의 활용 범위

OpenBSD 자체 가상화는 작은 수의 서버 가상 머신을 단순하고 명확한 구성으로 운영하는 환경에 적합하다. 기본 시스템만으로 하이퍼바이저, 가상 스위치, PF, 라우팅과 원격 관리 기능을 구성할 수 있다.

개발자는 새 OpenBSD 릴리스, -current 스냅샷, 네트워크 데몬과 설치 절차를 물리 장비와 분리하여 시험할 수 있다. 오류가 발생하면 가상 디스크를 교체하거나 새 가상 머신을 만들어 시험 환경을 빠르게 재구성할 수 있다.

OpenBSD와 Linux 서버를 한 호스트에 분리하여 DNS, 웹, 메일, 라우팅 시험과 빌드 작업을 수행할 수 있다. 각 가상 머신의 디스크, 네트워크와 관리 권한을 따로 지정하면 하나의 사용자 공간에 모든 서비스를 설치하는 것보다 운영 경계를 명확하게 만들 수 있다.

가상 스위치와 PF를 결합하면 방화벽·라우터 실습, 다중 네트워크 시험, VPN 게이트웨이와 고가용성 구성을 물리 스위치 없이 만들 수 있다. 서로 다른 routing domain과 사설 주소를 이용해 복잡한 네트워크 토폴로지를 재현할 수도 있다.

OpenBSD 자동 설치와 결합하면 반복 가능한 게스트 배포 환경을 만들 수 있다. 가상 머신을 네트워크 부팅하고 autoinstall 응답 파일과 siteXX.tgz를 사용하여 동일한 기본 구성을 여러 번 설치할 수 있다.

공개 인터넷 서비스를 가상 머신별로 나누면 하나의 서비스 침해가 다른 서비스의 파일과 프로세스에 직접 접근하는 범위를 줄일 수 있다. 그러나 가상화 자체만으로 완전한 보안 경계가 보장되는 것은 아니며 호스트와 vmd, 게스트 운영체제를 모두 최신 상태로 유지해야 한다.

호스트의 PF는 게스트 사이와 외부 네트워크의 통신을 제어할 수 있다. 게스트 내부 방화벽과 함께 사용하면 호스트 수준과 게스트 수준의 두 계층에서 접근 정책을 적용할 수 있다.

가상 머신은 전체 커널과 메모리를 각각 가지므로 단순한 프로세스 격리보다 자원 사용량이 크다. 많은 작은 서비스를 실행할 때에는 별도 사용자, chroot, pledgeunveil만으로 충분한지, 가상 머신 수준의 분리가 필요한지를 비교해야 한다.

그래픽 인터페이스가 없고 게스트 SMP를 지원하지 않으므로 일반 데스크톱 가상화, 다중 코어 컴파일 서버와 고성능 계산 작업에는 제약이 있다. GPU와 PCI 장치 직접 할당도 지원하지 않아 그래픽 가속이나 특수 하드웨어가 필요한 워크로드에는 적합하지 않다.

실시간 마이그레이션과 실행 중 하드웨어 변경이 없으므로 대규모 클라우드 오케스트레이션과 무중단 호스트 유지보수에는 한계가 있다. 가상 머신을 다른 호스트로 옮기려면 게스트를 정지하고 디스크와 필요한 상태를 안전하게 이전하는 운영 절차가 필요하다.

현재 관리형 스냅샷 기능도 제공되지 않으므로 업데이트 전 상태를 즉시 되돌리는 기능에 의존할 수 없다. 중요한 게스트는 정상 종료 기반 백업, 별도 디스크 복사와 응용 프로그램별 데이터 백업을 구성해야 한다.

이러한 제약은 vmm·vmd가 목표로 하는 범위를 보여준다. OpenBSD의 자체 가상화는 모든 하이퍼바이저 기능을 제공하기보다 OpenBSD 기본 시스템의 네트워크·보안·관리 도구와 자연스럽게 결합되는 작고 감사 가능한 가상 머신 환경을 지향한다.

그래픽과 데스크톱 환경

OpenBSD는 그래픽 사용자 환경을 선택적으로 설치할 수 있는 완전한 운영체제다. 기본 시스템에는 Xenocara라는 이름으로 관리되는 X Window System 구현, 그래픽 라이브러리, 글꼴, 터미널 에뮬레이터, 디스플레이 관리자와 여러 경량 윈도 관리자가 포함된다. 사용자는 이 기본 환경만으로 간결한 그래픽 작업 공간을 구성하거나, 패키지를 통해 GNOME, KDE Plasma, Xfce, MATE, LXQt와 여러 독립형 윈도 관리자를 추가할 수 있다.

OpenBSD는 특정 데스크톱 환경 하나를 공식 기본 사용자 인터페이스로 지정하지 않는다. 기본 설치가 제공하는 그래픽 환경은 완전한 통합 데스크톱보다 X 서버, 기본 X 프로그램, xenodm과 윈도 관리자를 조합한 전통적인 UNIX 워크스테이션 환경에 가깝다.

그래픽 환경의 사용 가능성은 프로세서 아키텍처, 그래픽 장치, 디스플레이 출력, 펌웨어와 드라이버 지원에 따라 크게 달라진다. 같은 OpenBSD 릴리스에서도 일반적인 amd64 노트북과 서버용 arm64 보드, 오래된 워크스테이션이 동일한 그래픽 기능과 성능을 제공하는 것은 아니다.

웹 브라우저, 오피스 프로그램, 이미지 편집기, 동영상 재생기와 데스크톱 환경은 대부분 포트와 패키지를 통해 설치한다. Firefox, Chromium, LibreOffice, GIMP, Inkscape, mpv와 VLC 같은 널리 알려진 프로그램도 패키지로 제공되지만, 지원 아키텍처와 하드웨어 가속 범위는 프로그램마다 다르다.[229]

Xenocara

Xenocara는 OpenBSD가 기본 시스템의 일부로 유지하는 X Window System 소스 트리다. X.Org의 소프트웨어를 기반으로 하지만 OpenBSD의 빌드 체계, 보안 정책, 지원 플랫폼과 장치 드라이버에 맞춘 수정 사항을 포함한다.

Xenocara라는 이름은 X.Org 코드 전체를 단순히 다른 이름으로 재배포한다는 뜻보다, OpenBSD가 X 서버와 관련 라이브러리·프로그램을 별도의 통합 소스 트리에서 직접 빌드하고 유지한다는 의미에 가깝다. OpenBSD의 저작권 정책은 Xenocara를 X.Org 코드를 개선하고 적극적으로 유지하는 기본 시스템 구성 요소로 설명한다.[230]

Xenocara에는 X 서버, X11 클라이언트 라이브러리, Mesa, 글꼴 처리 라이브러리, 입력 장치 지원, xterm, 여러 기본 X 프로그램과 그래픽 드라이버가 포함된다. 정식 릴리스에서는 이 구성 요소들이 OpenBSD 커널과 기본 사용자 공간에 맞춰 함께 빌드되고 시험된다.

Xenocara 파일은 설치 파일 세트로 나뉘어 제공된다. X 서버, 응용 프로그램, 라이브러리, 글꼴과 개발 파일을 필요에 따라 선택할 수 있으며, 일반적인 데스크톱 설치에서는 관련 파일 세트를 모두 설치하는 편이 단순하다.

기본 시스템 소스와 Xenocara 소스는 별도의 트리로 관리된다. 일반 시스템 소스는 주로 /usr/src, Xenocara 소스는 /usr/xenocara에 배치되며 각각의 빌드 절차를 따른다.

OpenBSD 7.9의 Xenocara는 X.Org 계통 X 서버와 Mesa 및 관련 구성 요소를 OpenBSD용 패치와 함께 제공한다. 각 릴리스는 업스트림의 최신 버전을 무조건 그대로 적용하기보다 OpenBSD에서 시험된 버전과 수정 사항을 통합한다.[231]

Xenocara에는 OpenBSD의 보안 구조에 맞춘 변경도 포함된다. X 서버의 권한 처리, 장치 접근과 프로세스 격리, 기본 프로그램의 pledge·unveil 적용 등이 릴리스마다 개선되어 왔다.

Xenocara는 OpenBSD 그래픽 환경의 기반이지만 데스크톱 셸이나 통합 설정 센터 자체를 의미하지는 않는다. 사용자는 그 위에 기본 윈도 관리자나 패키지로 설치한 데스크톱 환경을 실행한다.

X Window System

X Window System은 화면 출력, 창의 생성과 이동, 키보드·마우스 입력, 글꼴과 그래픽 자원에 접근하는 네트워크 투명형 그래픽 시스템이다. OpenBSD의 기본 그래픽 환경은 X11 프로토콜과 X.Org 계통 구현을 기반으로 한다.

X 환경에서 화면과 입력 장치를 관리하는 프로그램은 X 서버이며, 터미널 에뮬레이터와 웹 브라우저, 윈도 관리자 같은 프로그램은 X 클라이언트다. 서버와 클라이언트는 같은 컴퓨터에서 실행할 수도 있고 네트워크를 사이에 두고 서로 다른 컴퓨터에서 실행할 수도 있다.

OpenBSD 공식 FAQ는 대부분의 일반적인 하드웨어에서 X가 별도의 수동 설정 없이 동작한다고 설명한다. 커널 드라이버와 X 서버가 디스플레이와 입력 장치를 감지하면 전통적인 /etc/X11/xorg.conf 파일을 작성하지 않아도 그래픽 환경을 시작할 수 있다.[232]

X를 시작하는 권장 방법은 xenodm 디스플레이 관리자를 사용하는 것이다. 설치 과정에서 활성화하거나 이후 rcctl로 서비스를 켤 수 있으며, 그래픽 로그인 화면에서 사용자 인증 후 X 세션을 시작한다.

xenodm은 전통적인 startx보다 OpenBSD의 권한 분리와 인증 처리에 맞는 실행 경로를 제공한다. 공식 FAQ도 보안상의 이점을 이유로 xenodm 사용을 권장한다.[233]

사용자가 로그인하면 /etc/X11/xenodm/Xsession이 실행되고, 사용자 홈 디렉터리에 .xsession이 있으면 이를 읽는다. .xsession에는 배경 설정, 상태 표시 프로그램, 터미널과 마지막으로 실행할 윈도 관리자를 지정할 수 있다.

X 세션의 마지막 전경 프로세스는 보통 윈도 관리자나 데스크톱 세션이다. 해당 프로세스가 종료되면 사용자 세션도 끝나고 xenodm 로그인 화면으로 돌아간다.

OpenBSD의 기본 그래픽 계층은 현재도 X11을 중심으로 한다. Wayland 관련 라이브러리, Sway와 일부 Wayland용 프로그램이 포트에 존재하지만, 모든 하드웨어와 데스크톱 환경에서 X11을 완전히 대체하는 기본 그래픽 체계로 제공되는 것은 아니다.[234]

윈도 관리자

윈도 관리자는 X 서버가 만든 창의 위치, 크기, 테두리, 제목 표시줄, 키보드 단축키와 작업 공간을 관리한다. X 서버 자체는 창을 어떻게 배열하고 사용자에게 어떤 조작 방식을 제공할지를 결정하지 않는다.

OpenBSD 기본 시스템에는 cwm, fvwmtwm이 포함된다. 공식 FAQ는 이 세 윈도 관리자를 기본 제공 항목으로 명시한다.[235]

cwm은 OpenBSD가 직접 유지하는 가벼운 윈도 관리자다. 키보드 중심의 창 검색, 그룹, 가상 데스크톱과 간결한 설정 문법을 제공하며 별도의 패널이나 데스크톱 셸을 요구하지 않는다.

cwm은 기본 시스템과 함께 개발되므로 OpenBSD 환경에 자연스럽게 맞고 외부 패키지 의존성이 적다. 작은 메모리 사용량과 단순한 구성을 중시하는 사용자에게 적합하다.

fvwm은 전통적인 가상 데스크톱과 폭넓은 사용자 설정을 제공하는 윈도 관리자다. 메뉴, 아이콘, 창 장식과 동작을 설정 파일에서 세밀하게 조정할 수 있다.

twm은 X Window System의 고전적인 윈도 관리자 가운데 하나다. 기능과 외형은 매우 단순하지만 X 서버와 기본 프로그램만으로 최소 그래픽 환경을 구성할 수 있다.

외부 패키지에서는 i3, IceWM, Fluxbox, Awesome, Openbox 계열과 여러 타일링·스태킹 윈도 관리자를 사용할 수 있다. 현재 패키지 목록에는 i3, IceWM, Awesome과 Fluxbox 등이 제공된다.[236]

i3는 키보드 중심의 동적 타일링 방식을 사용하고, IceWM과 Fluxbox는 전통적인 데스크톱에 가까운 패널·메뉴와 가벼운 자원 사용을 제공한다. Awesome은 Lua를 이용한 광범위한 사용자 설정을 특징으로 한다.

독립형 윈도 관리자는 완전한 데스크톱 환경과 달리 파일 관리자, 알림 데몬, 전원 관리, 화면 잠금, 네트워크 애플릿과 설정 센터를 자동으로 제공하지 않을 수 있다. 사용자는 필요한 프로그램을 개별적으로 조합해야 한다.

기본 윈도 관리자와 외부 윈도 관리자는 .xsession의 마지막 명령으로 지정할 수 있다. 데스크톱 환경을 설치하지 않고도 터미널, 웹 브라우저, 파일 관리자와 상태 표시줄만 선택해 가벼운 작업 환경을 만들 수 있다.

데스크톱 환경

데스크톱 환경은 윈도 관리자 또는 컴포지터뿐 아니라 패널, 응용 프로그램 메뉴, 파일 관리자, 설정 프로그램, 알림, 화면 잠금과 세션 관리를 통합한 사용자 환경이다.

OpenBSD 기본 시스템에는 GNOME이나 KDE Plasma 같은 대형 데스크톱 환경이 포함되지 않는다. 이러한 환경은 포트·패키지로 설치하며 기본 시스템의 Xenocara와 여러 외부 라이브러리 위에서 실행한다.

GNOME은 핵심 데스크톱과 추가 응용 프로그램을 묶은 메타패키지로 제공된다. GNOME Shell, 설정 센터, 파일 관리자, 터미널과 여러 기본 응용 프로그램을 설치할 수 있다.[237]

KDE Plasma도 기본 데스크톱과 추가 응용 프로그램을 위한 패키지가 제공된다. Plasma 셸, 시스템 설정, 파일 관리자, KDE Frameworks와 Qt 기반 프로그램을 사용할 수 있다.[238]

Xfce는 비교적 가벼운 전통적 데스크톱 환경으로 제공된다. 패널, 응용 프로그램 메뉴, 파일 관리자, 세션 관리와 여러 플러그인을 포함하며 OpenBSD에서 완전한 데스크톱을 구성할 때 자주 선택되는 환경 가운데 하나다.[239]

MATE는 GNOME 2 계통의 전통적인 데스크톱 구성을 이어가는 환경이다. 기본 설치와 추가 응용 프로그램을 묶은 메타패키지가 제공된다.[240]

LXQt는 Qt 기반의 경량 데스크톱 환경이다. 패널, 세션 관리자, 설정 도구, 파일 관리자와 전원 관리 구성 요소를 패키지로 설치할 수 있다.[241]

Lumina와 일부 다른 데스크톱 환경도 포트에 존재한다. 다만 패키지가 존재한다는 사실이 모든 기능이 Linux 배포판과 동일하게 작동한다는 의미는 아니다. 운영체제별 전원 관리, 장치 검색, 서비스 관리와 권한 체계의 차이 때문에 일부 설정 모듈은 제한되거나 OpenBSD용 패치가 필요하다.

대형 데스크톱 환경은 D-Bus, polkit, 메시지 버스, 알림 데몬과 여러 백그라운드 서비스를 요구할 수 있다. 패키지 설치 후 제공되는 pkg-readme를 확인하여 필요한 서비스와 .xsession 초기화 항목을 구성해야 한다.

GNOME과 KDE Plasma는 사용할 수 있지만 OpenBSD가 해당 환경 전체를 기본 운영체제와 같은 범위로 직접 설계하는 것은 아니다. 업스트림 변경, 포트 유지보수 상태, 아키텍처와 그래픽 드라이버에 따라 제공 버전과 기능이 달라질 수 있다.

그래픽 드라이버

OpenBSD의 그래픽 지원은 커널의 DRM·KMS 계층, 프레임버퍼와 플랫폼별 디스플레이 드라이버, Xenocara의 X 서버와 Mesa 사용자 공간 드라이버가 함께 구성한다.

커널 모드 설정을 지원하는 장치에서는 커널이 화면 해상도, 출력 장치와 그래픽 메모리를 초기화한다. X 서버와 Mesa는 커널 인터페이스를 통해 화면 출력과 2D·3D 가속을 사용한다.

amd64 시스템에서는 인텔과 AMD 그래픽 장치가 가장 일반적인 지원 대상이다. 지원되는 세대에서는 기본 화면 출력, 다중 모니터, 해상도 변경과 Mesa 기반 OpenGL 가속을 사용할 수 있다.

OpenBSD/amd64 공식 페이지는 대부분의 그래픽 카드에서 X.Org 서버를 사용할 수 있다고 설명하지만, NVIDIA가 공개 문서 제공에 비협조적이라는 이유로 NVIDIA 장치 사용을 피할 것을 권장한다.[242]

최신 NVIDIA GPU용 독점 드라이버는 OpenBSD에서 제공되지 않는다. 일부 오래된 장치는 오픈 소스 드라이버나 기본 프레임버퍼로 제한적인 출력을 사용할 수 있지만 현대적인 가속과 전원 관리를 기대하기 어렵다.

AMD와 인텔 장치도 모든 세대와 기능이 동시에 지원되는 것은 아니다. 새로운 GPU는 업스트림 DRM 코드, 펌웨어, 개발 장비와 OpenBSD 포팅 작업이 필요하며 초기 지원에서는 절전, 외부 출력과 가속 기능에 제한이 있을 수 있다.

arm64에서는 Apple Silicon, Rockchip, Qualcomm과 여러 SoC의 디스플레이 지원이 플랫폼마다 다르다. 일부 시스템은 네이티브 디스플레이 드라이버와 가속을 제공하지만, 다른 보드는 단순 프레임버퍼나 제한된 출력만 사용할 수 있다.

X 서버가 시작된다고 반드시 3D 하드웨어 가속이 활성화된 것은 아니다. Mesa가 소프트웨어 렌더러를 사용할 수도 있으며, 이 경우 일반적인 2D 데스크톱은 동작하더라도 웹 브라우저, 고해상도 영상과 3D 프로그램의 성능이 낮을 수 있다.

다중 모니터, 회전, 해상도와 출력 배치는 xrandr로 조정할 수 있다. 데스크톱 환경의 디스플레이 설정 프로그램도 내부적으로 XRandR 인터페이스를 사용할 수 있다.

OpenBSD 7.9에서도 AMD GPU의 특정 패널 기능으로 인한 정지 문제를 피하기 위한 변경 등 실제 노트북과 디스플레이 안정성을 위한 수정이 계속 이루어지고 있다.[243]

오디오와 멀티미디어

OpenBSD의 기본 오디오 체계는 커널 오디오 드라이버와 sndio 라이브러리, sndiod 서버로 구성된다. 응용 프로그램은 일반적으로 하드웨어 장치를 직접 독점하지 않고 sndio 인터페이스를 통해 재생과 녹음을 수행한다.

sndiod는 여러 프로그램의 오디오 스트림을 혼합하고 샘플 형식을 변환하며 기본 출력 장치를 관리한다. 내부 사운드 장치와 USB 오디오 인터페이스를 각각 snd/0, snd/1 같은 이름으로 사용할 수 있다.[244]

일반 사용자는 sndioctl로 출력 음량과 sndio 제어 값을 변경할 수 있다. 장치별 하드웨어 믹서의 상세 설정은 root 권한의 mixerctl로 조정한다.

기본 시스템의 aucat은 WAV, AIFF와 AU 같은 비압축 오디오 파일을 재생하거나 녹음하고 오디오 형식을 변환할 수 있다. MIDI 장치는 midicat과 sndio의 MIDI 기능을 통해 연결할 수 있다.

MP3, AAC, Opus, FLAC, H.264, AV1과 다양한 컨테이너 형식은 외부 코덱과 프로그램을 통해 사용한다. FFmpeg, mpv, VLC와 여러 음악 재생기가 패키지로 제공된다.[245]

Firefox와 Chromium도 패키지로 제공되며 HTML5 오디오·영상 재생에 사용할 수 있다. Firefox의 전체 멀티미디어 기능에는 FFmpeg 패키지가 추가로 필요할 수 있다.[246]

오디오 녹음은 개인정보 보호를 위해 기본적으로 비활성화된다. 마이크나 녹음 기능을 사용할 때에는 kern.audio.record를 명시적으로 활성화해야 한다.[247]

웹캠과 영상 캡처도 기본적으로 차단된다. 사용자가 kern.video.record를 활성화하고 해당 /dev/video 장치에 대한 접근 권한을 부여해야 프로그램이 카메라를 사용할 수 있다.

WebRTC 화상 통화나 브라우저 기반 화면 공유는 이러한 녹음 권한뿐 아니라 브라우저의 pledge·unveil, 공유 메모리와 장치 접근 제한의 영향을 받을 수 있다. 일부 기능은 Linux나 Windows의 같은 브라우저와 동작 방식이 다를 수 있다.

하드웨어 영상 디코딩과 GPU 가속은 그래픽 드라이버와 Mesa, 프로그램별 지원에 달려 있다. 프로그램 패키지가 VA-API 같은 기능을 포함하더라도 실제 장치와 OpenBSD 드라이버가 이를 지원해야 한다.

전문적인 저지연 오디오, 대규모 영상 편집과 상용 DRM 스트리밍은 제한될 수 있다. sndio는 낮은 지연 설정과 MIDI를 지원하지만, 특정 상용 플러그인과 폐쇄형 미디어 서비스가 OpenBSD용 바이너리를 제공하지 않는 경우가 많다.

노트북 지원

OpenBSD는 여러 amd64와 arm64 노트북에서 배터리, 전원 버튼, 화면 밝기, 덮개 감지, 절전과 재개 기능을 지원한다. 실제 동작은 ACPI·플랫폼 펌웨어와 각 장치 드라이버의 지원 상태에 따라 달라진다.

apmd는 배터리 상태와 전원 이벤트를 감시하고 절전, 재개, 저전력 경고와 전원 종료 시 동작을 실행한다. 성능 정책을 자동으로 조정하거나 배터리 상태에 따라 스크립트를 실행할 수도 있다.[248]

배터리와 전원 정보는 apm, sysctl과 데스크톱 환경의 전원 관리 도구에서 확인할 수 있다. 데스크톱 패널의 배터리 표시 기능은 이러한 커널 정보를 사용한다.

화면 밝기는 그래픽·백라이트 드라이버와 wsconsctl, 전용 단축키 또는 데스크톱 환경의 도구를 통해 조정할 수 있다. 키보드 백라이트와 기능 키는 노트북 모델별 ACPI·HID 드라이버 지원이 필요하다.

터치패드, 트랙포인트와 외부 마우스는 wscons 입력 계층과 X 입력 드라이버를 통해 동작한다. 멀티터치 제스처와 정밀 스크롤 지원은 장치와 데스크톱 프로그램에 따라 차이가 있다.

무선 네트워크는 인텔 계열을 비롯한 여러 칩셋에서 지원되지만 펌웨어 설치가 필요할 수 있다. 일부 최신 Broadcom, Realtek과 MediaTek 장치는 지원되지 않거나 기능이 제한될 수 있다.

Bluetooth는 일부 컨트롤러와 제한된 용도로 사용할 수 있지만, 일반 소비자 데스크톱에서 기대하는 모든 Bluetooth 오디오·주변기기 환경이 완전하게 제공된다고 보기는 어렵다.

절전과 재개는 노트북 사용성에서 중요한 요소다. OpenBSD는 릴리스마다 특정 ThinkPad와 Apple Silicon 시스템의 USB, NVMe, GPU, 터치패드와 전원 관리 문제를 수정하고 있다.[249]

같은 제품군에서도 BIOS 버전, 무선 카드, 패널과 CPU 세대가 달라질 수 있다. OpenBSD 노트북을 선택할 때에는 제품명만 확인하기보다 실제 dmesg, 공식 플랫폼 자료와 사용자 시험 기록을 참고하는 것이 좋다.

ThinkPad 계열은 공개된 하드웨어 정보와 개발자의 사용 경험이 비교적 많아 OpenBSD 노트북으로 자주 사용되지만, 모든 ThinkPad 모델이 동일한 수준으로 지원되는 것은 아니다.

지문 인식기, 얼굴 인식 카메라, Thunderbolt 도킹, 최신 절전 상태, 하이브리드 GPU와 특수 제조사 제어 프로그램은 지원되지 않거나 제한될 수 있다. 배터리 지속 시간도 제조사 제공 Windows·macOS 드라이버보다 짧을 수 있다.

데스크톱 운영체제로서의 활용

OpenBSD는 서버와 네트워크 장비에만 사용할 수 있는 운영체제가 아니다. 지원되는 그래픽·오디오·입력 장치를 갖춘 컴퓨터에서는 웹 탐색, 문서 작성, 프로그래밍, 원격 관리와 일반적인 UNIX 워크스테이션 작업에 사용할 수 있다.

기본 Xenocara와 cwm만 사용하면 외부 데스크톱 환경 없이도 가벼운 작업 환경을 만들 수 있다. xterm, 웹 브라우저, 편집기와 필요한 응용 프로그램을 조합하는 방식은 단순성과 낮은 자원 사용량을 중시하는 사용자에게 적합하다.

보다 통합된 환경을 원하는 사용자는 Xfce, MATE, LXQt, GNOME 또는 KDE Plasma를 설치할 수 있다. 파일 관리자, 패널, 알림, 화면 잠금과 설정 도구를 갖춘 일반적인 데스크톱 사용 방식도 가능하다.

Firefox와 Chromium, LibreOffice, GIMP, Inkscape, Thunderbird, mpv, VLC와 여러 개발 도구가 패키지로 제공되므로 일반적인 웹·문서·개발 작업의 상당 부분을 수행할 수 있다.[250]

OpenBSD를 데스크톱으로 사용할 때의 강점은 기본 시스템과 문서의 일관성, 작은 기본 환경, 보안 기능, UNIX 개발 도구와 네트워크 관리 기능에 있다. 서버와 같은 설정·명령 체계를 로컬 워크스테이션에서도 그대로 사용할 수 있다.

반면 상용 데스크톱 소프트웨어와 게임 호환성은 제한적이다. Adobe Creative Cloud, Microsoft Office 데스크톱판, 대부분의 상용 게임과 제조사 전용 주변기기 프로그램은 OpenBSD용으로 제공되지 않는다.

Steam과 최신 상용 게임 생태계도 일반적인 지원 대상이 아니다. Linux 바이너리 호환 계층과 Proton을 기반으로 하는 게임 환경을 그대로 사용할 수 없으며, 커널 수준 안티치트와 독점 GPU 드라이버를 요구하는 게임은 실행하기 어렵다.

영상 스트리밍 서비스의 DRM, 화상회의의 화면 공유, GPU 가속 웹 콘텐츠와 하드웨어 영상 디코딩도 브라우저·코덱·드라이버 조합에 따라 제약이 생길 수 있다.

프린터, 스캐너, 태블릿과 특수 오디오 장치는 공개 표준이나 지원되는 USB 클래스를 사용할 때 동작하기 쉽다. 제조사 전용 드라이버와 설정 프로그램이 필요한 장치는 기능이 제한될 수 있다.

GNOME이나 KDE Plasma 같은 대형 환경을 실행할 수는 있지만, OpenBSD의 데스크톱 경험이 이들 환경을 중심으로 설계되는 것은 아니다. 일부 Linux 전용 통합 기능이나 systemd·udev를 전제로 한 구성 요소는 OpenBSD용 대체 구현과 포트 패치를 사용하거나 기능이 비활성화될 수 있다.

Wayland용 프로그램과 Sway 같은 컴포지터가 패키지에 존재하지만, OpenBSD의 기본적이고 가장 널리 시험된 데스크톱 경로는 여전히 Xenocara 기반 X11이다. Wayland 사용 가능성은 그래픽 장치와 개별 포트의 상태를 확인해야 한다.

따라서 OpenBSD는 최신 소비자용 데스크톱의 모든 기능과 상용 응용 프로그램 호환성을 우선하는 사용자보다, 시스템을 직접 구성하고 UNIX 환경과 보안·네트워크 기능을 중시하는 사용자에게 더 적합하다. 하드웨어를 신중하게 선택하고 필요한 패키지를 구성하면 일상용 노트북이나 개발 워크스테이션으로 사용할 수 있지만, 지원되지 않는 장치와 프로그램을 다른 운영체제와 같은 방식으로 사용할 수 있다고 기대해서는 안 된다.

개발 환경

시스템 컴파일러

C 개발 환경

make와 빌드 도구

디버거

시스템 헤더와 라이브러리

포트 개발

커널 개발

크로스 플랫폼 소프트웨어 개발

회귀 시험과 코드 검토

주요 프로젝트와 파생 소프트웨어

OpenSSH

LibreSSL

OpenBGPD

OpenSMTPD

OpenNTPD

PF

CARP

tmux

기타 구성 요소

표준과 호환성

POSIX

BSD 인터페이스

유닉스 계열 소프트웨어 호환성

Linux와의 소스 호환성

바이너리 호환성

네트워크 표준

암호화 표준

오래된 인터페이스의 제거

개발 체계

프로젝트 조직

테오 드 라트

개발자 공동체

CVS 저장소

메일링 리스트

코드 검토

해커톤

오류 보고

보안 취약점 공개

재정과 후원

라이선스와 배포 정책

허용적 자유 소프트웨어 라이선스

BSD와 ISC 계열 라이선스

소스 코드 재사용

비자유 라이선스에 대한 정책

펌웨어 재배포

암호화 소프트웨어의 배포

상표와 삽화

활용 분야

방화벽과 라우터

네트워크 기반 시설

가상 사설망 게이트웨이

DNS와 메일 서버

웹과 응용 프로그램 서버

보안 장비

개발 및 연구 환경

데스크톱과 노트북

임베디드 시스템

교육

다른 운영체제와의 관계

NetBSD

FreeBSD

DragonFly BSD

BSD 계통 운영체제

Linux

상용 UNIX

macOS

보안 중심 운영체제

영향

운영체제 보안 기술에 미친 영향

권한 분리와 샌드박싱

네트워크 소프트웨어

OpenSSH의 보급

PF와 네트워크 관리

암호화 라이브러리

코드 감사와 안전한 기본값

자유 소프트웨어 개발 문화

장점과 한계

장점

한계

적합한 환경

선택 시 고려 요소

관련 문서

  1. OpenBSD 공식 웹사이트
  2. OpenBSD: Security
  3. OpenBSD: Innovations
  4. OpenSSH 프로젝트의 역사
  5. LibreSSL 공식 웹사이트
  6. OpenBSD: Cryptography
  7. OpenBSD PF 사용자 안내서
  8. OpenBSD 공식 웹사이트
  9. OpenBSD 공식 웹사이트
  10. OpenBSD: Pruning and Polishing
  11. OpenBSD 저작권 정책
  12. OpenBSD: Security
  13. OpenBSD 프로젝트 목표
  14. OpenBSD 프로젝트 목표
  15. Developing Software in a Hostile Environment
  16. Better Documentation
  17. Getting Started with OpenBSD Device Driver Development
  18. OpenBSD FAQ의 CARP 설명
  19. OpenBSD Release Songs의 라이선스·NDA 정책 설명
  20. OpenBSD FAQ: Package Management
  21. pkg_add(1) — OpenBSD manual pages
  22. OpenBSD Porter's Handbook
  23. OpenBSD FAQ: Introduction to OpenBSD
  24. files.conf(5) — OpenBSD manual pages
  25. hier(7) — OpenBSD manual pages
  26. OpenBSD FAQ: Introduction to OpenBSD
  27. OpenBSD FAQ: Introduction to OpenBSD
  28. OpenBSD FAQ: Introduction to OpenBSD
  29. man(1) — OpenBSD manual pages
  30. ports(7) — OpenBSD manual pages
  31. OpenBSD FAQ: Package Management
  32. OpenBSD FAQ: Package Management
  33. pkg_add(1) — OpenBSD manual pages
  34. OpenBSD Porter's Handbook
  35. intro(9) — OpenBSD 커널 개발자 매뉴얼
  36. pledge(2) — OpenBSD 매뉴얼
  37. unveil(2) — OpenBSD 매뉴얼
  38. pledge(2) — OpenBSD 매뉴얼
  39. vfs(9) — OpenBSD 커널 개발자 매뉴얼
  40. bus_space(9) — OpenBSD 커널 개발자 매뉴얼
  41. spl(9) — OpenBSD 커널 개발자 매뉴얼
  42. timeout(9) — OpenBSD 커널 개발자 매뉴얼
  43. securelevel(7) — OpenBSD 매뉴얼
  44. pledge(2) — OpenBSD 매뉴얼
  45. unveil(2) — OpenBSD 매뉴얼
  46. random(4) — OpenBSD 매뉴얼
  47. OpenBSD: Security
  48. OpenBSD: Security
  49. OpenBSD 3.3 릴리스 정보
  50. pledge(2) — OpenBSD 매뉴얼
  51. unveil(2) — OpenBSD 매뉴얼
  52. OpenBSD: Innovations
  53. OpenBSD: Innovations
  54. OpenBSD: Innovations
  55. OpenBSD: Innovations
  56. malloc(3) — OpenBSD 매뉴얼
  57. pinsyscalls(2) — OpenBSD 매뉴얼
  58. random(4) — OpenBSD 매뉴얼
  59. arc4random(3) — OpenBSD 매뉴얼
  60. LibreSSL 공식 웹사이트
  61. doas(1) — OpenBSD 매뉴얼
  62. doas.conf(5) — OpenBSD 매뉴얼
  63. OpenBSD Errata and Patches
  64. OpenBSD FAQ: Following -current
  65. OpenBSD FAQ: System Management
  66. route(8) — OpenBSD 매뉴얼
  67. OpenBSD 6.5 변경 사항
  68. pfctl(8) — OpenBSD 매뉴얼
  69. OpenBSD PF 사용자 안내서
  70. pf.conf(5) — OpenBSD 매뉴얼
  71. OpenBSD PF: Network Address Translation
  72. pf.conf(5) — OpenBSD 매뉴얼
  73. OpenBGPD 공식 웹사이트
  74. route(8) — OpenBSD 매뉴얼
  75. iked(8) — OpenBSD 매뉴얼
  76. wg(4) — OpenBSD 매뉴얼
  77. OpenBSD FAQ: Wireless Networking
  78. ifconfig(8) — OpenBSD 매뉴얼
  79. bridge(4) — OpenBSD 매뉴얼
  80. vether(4) — OpenBSD 매뉴얼
  81. vlan(4) — OpenBSD 매뉴얼
  82. carp(4) — OpenBSD 매뉴얼
  83. pfsync(4) — OpenBSD 매뉴얼
  84. OpenBSD FAQ: CARP
  85. OpenBSD: Privilege Separation
  86. OpenBSD 6.5 변경 사항
  87. fstab(5) — OpenBSD 매뉴얼
  88. OpenBSD 6.7 릴리스 정보
  89. newfs(8) — OpenBSD 매뉴얼
  90. fsck_ffs(8) — OpenBSD 매뉴얼
  91. disklabel(8) — OpenBSD 매뉴얼
  92. softraid(4) — OpenBSD 매뉴얼
  93. bioctl(8) — OpenBSD 매뉴얼
  94. OpenBSD FAQ: Disk Setup — Full Disk Encryption
  95. umass(4) — OpenBSD 매뉴얼
  96. mount_msdos(8) — OpenBSD 매뉴얼
  97. exports(5) — OpenBSD 매뉴얼
  98. mount_nfs(8) — OpenBSD 매뉴얼
  99. chflags(1) — OpenBSD 매뉴얼
  100. fdisk(8) — OpenBSD 매뉴얼
  101. bioctl(8) — OpenBSD 매뉴얼
  102. vnconfig(8) — OpenBSD 매뉴얼
  103. fork(2) — OpenBSD 매뉴얼
  104. execve(2) — OpenBSD 매뉴얼
  105. wait(2) — OpenBSD 매뉴얼
  106. nice(1) — OpenBSD 매뉴얼
  107. renice(8) — OpenBSD 매뉴얼
  108. procmap(1) — OpenBSD 매뉴얼
  109. useradd(8) — OpenBSD 매뉴얼
  110. id(1) — OpenBSD 매뉴얼
  111. OpenBSD 7.1 릴리스 정보
  112. rcctl(8) — OpenBSD 매뉴얼
  113. login.conf(5) — OpenBSD 매뉴얼
  114. getrlimit(2) — OpenBSD 매뉴얼
  115. ksh(1) — OpenBSD 매뉴얼
  116. rcctl(8) — OpenBSD 매뉴얼
  117. OpenBSD 7.1 릴리스 정보
  118. rc.d(8) — OpenBSD 매뉴얼
  119. ps(1) — OpenBSD 매뉴얼
  120. top(1) — OpenBSD 매뉴얼
  121. systat(1) — OpenBSD 매뉴얼
  122. fstat(1) — OpenBSD 매뉴얼
  123. pstat(8) — OpenBSD 매뉴얼
  124. vmstat(8) — OpenBSD 매뉴얼
  125. ktrace(1) — OpenBSD 매뉴얼
  126. kdump(1) — OpenBSD 매뉴얼
  127. OpenBSD 7.1 릴리스 정보
  128. OpenBSD FAQ: Introduction to OpenBSD
  129. ksh(1) — OpenBSD 매뉴얼
  130. awk(1) — OpenBSD 매뉴얼
  131. OpenBSD FAQ: System Management
  132. OpenBSD FAQ: Package Management
  133. vi(1) — OpenBSD 매뉴얼
  134. mg(1) — OpenBSD 매뉴얼
  135. make(1) — OpenBSD 매뉴얼
  136. OpenBSD FAQ: Building the System from Source
  137. init(8) — OpenBSD 매뉴얼
  138. rc(8) — OpenBSD 매뉴얼
  139. cron(8) — OpenBSD 매뉴얼
  140. crontab(5) — OpenBSD 매뉴얼
  141. syslogd(8) — OpenBSD 매뉴얼
  142. newsyslog(8) — OpenBSD 매뉴얼
  143. OpenBSD FAQ: Package Management
  144. pkg_add(1) — OpenBSD 매뉴얼
  145. pkg_create(1) — OpenBSD 매뉴얼
  146. pkg_add(1) — OpenBSD 매뉴얼
  147. pkg_add(1) — OpenBSD 매뉴얼
  148. pkg_delete(1) — OpenBSD 매뉴얼
  149. packages(7) — OpenBSD 패키지 관리 규칙
  150. pkg_info(1) — OpenBSD 매뉴얼
  151. pkg_mklocatedb(1) — OpenBSD 매뉴얼
  152. packages(7) — OpenBSD 패키지 관리 규칙
  153. OpenBSD Porter's Handbook
  154. ports(7) — OpenBSD 매뉴얼
  155. OpenBSD Porting Guide
  156. signify(1) — OpenBSD 매뉴얼
  157. package(5) — OpenBSD 패키지 형식
  158. pkg_add(1) — OpenBSD 매뉴얼
  159. pkg_sign(1) — OpenBSD 매뉴얼
  160. packages(7) — OpenBSD 패키지 관리 규칙
  161. OpenBSD FAQ: Installation Guide
  162. install.site(5) — OpenBSD 매뉴얼
  163. OpenBSD FAQ: Disk Setup
  164. boot(8) — OpenBSD 매뉴얼
  165. init(8) — OpenBSD 매뉴얼
  166. rc(8) — OpenBSD 매뉴얼
  167. shutdown(8) — OpenBSD 매뉴얼
  168. rc.shutdown(8) — OpenBSD 매뉴얼
  169. sysmerge(8) — OpenBSD 매뉴얼
  170. autoinstall(8) — OpenBSD 매뉴얼
  171. install.site(5) — OpenBSD 매뉴얼
  172. sshd_config(5) — OpenBSD 매뉴얼
  173. init(8) — OpenBSD 매뉴얼
  174. OpenBSD FAQ: System Management
  175. OpenBSD FAQ: Installation Guide
  176. OpenBSD 공식 웹사이트
  177. OpenBSD FAQ: Following -current and Using Snapshots
  178. OpenBSD FAQ
  179. OpenBSD FAQ: Building the System from Source
  180. OpenBSD Ports: Working with Ports
  181. sysupgrade(8) — OpenBSD 매뉴얼
  182. pkg_add(1) — OpenBSD 매뉴얼
  183. OpenBSD FAQ: Introduction to OpenBSD
  184. OpenBSD Upgrade Guide: 7.8 to 7.9
  185. sysupgrade(8) — OpenBSD 매뉴얼
  186. syspatch(8) — OpenBSD 매뉴얼
  187. OpenBSD 7.9 Errata
  188. pkg_add(1) — OpenBSD 매뉴얼
  189. OpenBSD Errata and Patches
  190. OpenBSD: Security
  191. OpenBSD 7.9 Errata
  192. OpenBSD: Platforms
  193. OpenBSD 7.9 릴리스 정보
  194. OpenBSD 7.9 Errata
  195. OpenBSD/amd64
  196. OpenBSD/arm64
  197. OpenBSD 7.9 Errata
  198. OpenBSD/armv7
  199. OpenBSD/i386
  200. OpenBSD/powerpc64
  201. OpenBSD/riscv64
  202. Porting OpenBSD to RISC-V ISA
  203. OpenBSD/hppa
  204. OpenBSD: Platforms
  205. fw_update(8) — OpenBSD 매뉴얼
  206. OpenBSD 7.9 릴리스 정보
  207. OpenBSD FAQ: Installation Guide
  208. OpenBSD FAQ: Virtualization
  209. vmm(4) — OpenBSD 7.9 매뉴얼
  210. OpenBSD FAQ: Virtualization
  211. OpenBSD 7.8 변경 기록
  212. OpenBSD 7.8 릴리스 정보
  213. vmd(8) — OpenBSD 매뉴얼
  214. vm.conf(5) — OpenBSD 매뉴얼
  215. vmmci(4) — OpenBSD 매뉴얼
  216. vm.conf(5) — OpenBSD 매뉴얼
  217. OpenBSD FAQ: Virtualization
  218. vmctl(8) — OpenBSD 매뉴얼
  219. OpenBSD FAQ: Virtualization
  220. vio(4) — OpenBSD 매뉴얼
  221. vm.conf(5) — OpenBSD 매뉴얼
  222. OpenBSD FAQ: Virtualization
  223. vmctl(8) — OpenBSD 매뉴얼
  224. OpenBSD FAQ: Virtualization
  225. virtio(4) — OpenBSD 매뉴얼
  226. vmx(4) — OpenBSD 매뉴얼
  227. vmt(4) — OpenBSD 매뉴얼
  228. hyperv(4) — OpenBSD 매뉴얼
  229. OpenBSD 패키지 목록
  230. OpenBSD 저작권 정책
  231. OpenBSD 7.9 릴리스 정보
  232. OpenBSD FAQ: The X Window System
  233. OpenBSD FAQ: The X Window System
  234. OpenBSD 패키지 목록의 Sway
  235. OpenBSD FAQ: The X Window System
  236. OpenBSD 패키지 목록
  237. OpenBSD 패키지 목록의 GNOME
  238. OpenBSD 패키지 목록의 KDE Plasma
  239. OpenBSD 패키지 목록의 Xfce
  240. OpenBSD 패키지 목록의 MATE
  241. OpenBSD 패키지 목록의 LXQt
  242. OpenBSD/amd64
  243. OpenBSD 7.9 릴리스 정보
  244. OpenBSD FAQ: Multimedia
  245. OpenBSD 멀티미디어 패키지 목록
  246. OpenBSD Firefox 포트 안내
  247. OpenBSD FAQ: Multimedia
  248. apmd(8) — OpenBSD 매뉴얼
  249. OpenBSD 7.9 릴리스 정보
  250. OpenBSD 패키지 목록