
📖 목차
폐쇄망(Air-gapped) 관리 비용과 편리성의 역설
폐쇄망(혹은 에어갭)에서 Red Hat Enterprise Linux(이하 RHEL)를 운용할 때, 전용 관리 도구인 RHEL Satellite 없이 서비스 하는 것은 Red Hat이 제공하는 지원을 절반을 포기하는 것과 같다. 때문에 비용을 절감을 위해 RHEL 1:1 클론인 Rocky Linux를 선택하거나, 반대로 관리의 편의성을 위한 막대한 비용을 들여 RHEL Satellite를 도입하는 것이 일반적인 선택지일 것이다.
하지만, RHEL Satellite 도입은 그리 간단한 문제가 아니다. 추가적인 인프라 리소스와 관리 공수가 요구되며 RHEL 호스트당 Add-on 라이선스 추가 비용이 발생하고 Satellite 자체의 막대한 도입 비용은 별개이다.
그래서 이러한 RHEL Satellite 없이 RHEL을 운용해야하는 환경, 혹은 Rocky Linux 기반의 폐쇄망 관리를 위한 글이다. 비용과 관리 효율의 타협점으로서, 외부 인터넷 연결 없이 폐쇄망에 안정적으로 패키지를 공급할 수 있는 저장소 (a.k.a 로컬레포) 구축 가이드라인을 공유한다.
환경 설계
들어가기 앞서서 당연하게도 추가적인 인프라 리소스와 관리가 요구되는건 이 글도 동일하다. 공짜 점심 없습니다. 🙁
크게 다음 레이어를 통해 어떻게 데이터를 반입하고 들여야할지 살펴보자.
- 레이어 1 (외부망): Red Hat CDN / Rocky Linux Mirror —-> 개발자 / 작업용 PC (reposync 수행 및 메타데이터 추출)
↓ - 레이어 2 (망연계): USB/보안 USB, 망연계 솔루션 (데이터반입)
↓ - 레이어 3 (폐쇄망 내부): 내부 Repo HTTP 서버 (nginx를 통해 서비스 제공)
이와 같은 구성으로 외부망 → 망연계 → 폐쇄망 방향으로 설계된다.
구성하기
외부망에서 Repo 데이터 받아오기
우선 Repo를 받아올 수 있는 해당 환경이 있다고 가정하고 진행한다. RHEL의 경우 RHEL 배포판(8/9/10 버전)이 Rocky Linux의 경우 Rocky Linux 배포판(8/9/10 버전)이 설치되어 있는 환경에서 진행해야한다.
이러한 기본적인 환경은 VM(Oracle VirtualBox 또는 VMware workstation)을 통해 작업해도 되고, WSL(Windows Subsystem for Linux) 환경에서 진행하는 방법도 있다.
개인적으로 데이터를 쉽게 추출하기 위해 WSL 환경에서 작업하는 것을 추천한다. WSL은 Linux와 Windows간 데이터를 손쉽게 주고 받을 수 있어(9P 프로토콜) 추출하기 좋기 때문이다.
라이선스 확인
RHEL과 Rocky Linux의 Repo 데이터 받아오는 전제조건은 서로 다르다.
RHEL은 유료 라이선스 기반의 OS이므로 서브스크립션(Subscription) 활성화가 필요하다.
개인 테스트 목적이라면 레드햇에서 제공하는 개인 개발자 계정을 등록 후 서브스크립션을 활성화할 수 있다. 다만, 상용 환경(Production)에서 사용할 목적이라면 서브스크립션 잔여 수량이나 계약 조건을 반드시 먼저 확인해야 한다.
Rocky Linux는 오픈소스 프로젝트이므로 별도의 서브스크립션 등록 절차나 라이선스 제약 없이 자유롭게 Repo 데이터를 가져올 수 있다.
Repo 데이터 당겨오기
우선 가져올 호스트에 dnf-utils(과거 yum-utils)를 설치하여 레포를 당겨올 환경을 구성하자.(reposync만 사용할 경우 dnf-plugins-core만 설치하면 된다.)
yum과 dnf 명령어는 동일한 명령어라 생각해도 되며 패키지를 설치하는 명령어이므로 편한 명령어로 입력해도 된다.
참고로 yum 명령어를 개선한 것이 dnf 명령어이며 RHEL/Rocky Linux 8 버전 이후부터는 터미널에 yum을 입력해도 내부적으로는 dnf 명령어가 알아서 대체되어 작동되므로 편한 명령어를 사용하면 된다.
sudo dnf install dnf-utils -y이제 Repo를 받아올 준비가 되었으면 배포판에 맞춰서 다음과 같이 하자. 이 가이드라인에서는 8 버전을 기준으로하며 배포판이 동일한 버전을 업데이트 할 경우 아래의 명령어가 적용이 가능하며 배포판 버전이 다를 경우에는 별도의 방법이 필요하다.
# RHEL
sudo dnf reposync \
--repoid=rhel-8-for-x86_64-baseos-rpms \
--repoid=rhel-8-for-x86_64-appstream-rpms \
--newest-only \
-p /repo/
sudo createrepo_c /repo/rhel-8-for-x86_64-baseos-rpms/
sudo createrepo_c /repo/rhel-8-for-x86_64-appstream-rpms/# Rocky Linux
sudo dnf reposync \
--repoid=baseos \
--repoid=appstream \
--newest-only \
-p /repo/
sudo createrepo_c /repo/baseos/
sudo createrepo_c /repo/appstream/만약 명령어가 작동이 안될 경우 /etc/yum.repos.d/ 디렉터리에 있는 repo 파일에 기재된 [] 로 감싸진 네이밍을 확인하거나 dnf repolist 명령어로 repoid를 확인하면 된다.
주의할 점으로는 이번 글은 특정 버전의 최신 버전을 가지고 로컬 레포를 구성하는 것이므로 내부망에서 특정 버전의 패키지가 필요한 상황이 빈번하게 발생한다면 newest-only 옵션과 createrepo_c 명령어를 제외하고 –download-metadata를 넣어줘서 대량의 패키지 파일을 가져와야 한다.
nginx를 통해 Repository 웹서버 구축
이 글에서는 간단하게 구축이 가능한 nginx를 통해 저장소 서버를 구축한다.
# nginx 설치 및 자동 실행
sudo dnf install nginx -y
sudo systemctl enable --now nginx
# firewalld를 사용할 경우 아래 명령어를 통해 80포트를 개방해준다. (iptables나 nftables를 사용한다면 명령어 생략한다. 개방하는 법 아시잖아요...)
sudo firewall-cmd --permanent --add-port=80/tcp
sudo firewall-cmd --reload/etc/nginx/conf.d 디렉터리에 다음과 같은 파일을 만들어주자. 이름은 적당하게 repo.conf와 같이 지어주면 된다.
server {
listen 80;
server_name repo.local;
root /repo;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
keepalive_requests 10000;
location / {
autoindex on;
autoindex_exact_size off;
autoindex_localtime on;
}
access_log /var/log/nginx/repo_access.log main buffer=16k;
error_log /var/log/nginx/repo_error.log;
}
다 작성 후에는 다음과 같이 문법 검사를 하고 이상이 없다면 서비스 재시작을 해주면된다.
sudo nginx -t
sudo systemctl reload nginxSELinux가 활성화 되있을 경우
국내 환경에서는 selinux가 매번 끄는 것이 기본 옵션이 된 상황이지만, 웬만해서 selinux는 꼭 활성화 해두고 쓰자. 저장소 서버가 공격당해 해킹당해 rpm 파일들이 악성코드로 감염된다면 큰 문제가 될 것이다. 물론, 하단에서 설명할 호스트들의 GPG Key를 이용한 인증을 한번 더 거친다면 최악의 상황은 피할 수 있을 것이다.
sudo semanage fcontext -a -t httpd_sys_content_t "/repo(/.*)?"
sudo restorecon -R -v /repo/호스트에서 설정
이제 호스트에서 설정은 간단하다. 기존 로컬 레포를 구성하는것과 같이 /etc/yum.repos.d/ 디렉터리에 Repo를 생성해주면 된다.
sudo mv /etc/yum.repos.d/* /etc/yum.repos.d/*.bak
sudo vim /etc/yum.repos.d/local-sever.repo각 호스트들에서 gpgcheck를 설정함과 동시에 gpgkey 경로를 지정해줄 것이다. 해당 Key 파일을 통해 rpm 파일이 변조되었는지 구분하여 서버 패키지 설치에 있어 안정성을 더 해줄것이다.
RHEL 호스트의 레포 설정
[local-baseos]
name=RHEL 8 BaseOS
baseurl=http://[nginx_SERVER_IP]/repo/rhel-8-for-x86_64-baseos-rpms/
enabled=1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-redhat-release
[local-appstream]
name=RHEL 8 AppStream
baseurl=http://[nginx_SERVER_IP]/repo/rhel-8-for-x86_64-appstream-rpms/
enabled=1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-redhat-releaseRocky Linux의 레포 설정
[local-baseos]
name=Rocky Linux BaseOS
baseurl=http://[nginx_SERVER_IP]/repo/baseos/
enabled=1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-rockyofficial
[local-appstream]
name=Rocky Linux AppStream
baseurl=http://[nginx_SERVER_IP]/repo/appstream/
enabled=1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-rockyofficial마치며
이렇게 완료 후 업데이트를 하거나 로컬 레포지터리 구성을 통해 서버를 최신화하고 각 호스트에 별도 로컬 레포지터리 없이 용량 낭비를 하지 않고 한 서버를 바라보게 하여 처리할 수 있다.