alloy 설치 과정에서 gpg 인증에 실패하는 이슈가 있어 학습하게 되었습니다.
GPG (GNU Privacy Guard) 는 파일의 변조 여부를 판단하기 위한 전자 서명 도구입니다.
핵심 원리는 비대칭 암호화(Asymmetric Encryption)입니다:
| 구분 | Private Key (비밀 키) | Public Key (공개 키) |
|---|---|---|
| 보유자 | 배포자만 보유 | 누구나 획득 가능 |
| 용도 | 서명 생성, 복호화 | 서명 검증, 암호화 |
| 유출 시 영향 | 치명적 (키 로테이션 필요) | 영향 없음 (공개 목적) |
Linux 패키지 배포에서 GPG가 동작하는 전체 흐름은 다음과 같습니다.
[패키지 배포자 - Grafana Labs]
1. GPG 키 쌍 생성 (Private Key + Public Key)
2. Private Key로 패키지(.rpm/.deb)에 서명
3. 서명된 패키지 + Public Key를 저장소에 게시
↓ (네트워크를 통해 다운로드)
[사용자 시스템 - 서버]
4. Public Key를 시스템 키링에 등록 (rpm --import / apt-key)
5. 패키지 다운로드
6. Public Key로 서명 검증
├─ 검증 성공 → 설치 진행
└─ 검증 실패 → 설치 차단 (GPG check FAILED)
RPM 기반 시스템의 저장소 설정 파일(.repo)에는 두 가지 GPG 검증 옵션이 있습니다:
[grafana]
name=grafana
baseurl=https://rpm.grafana.com
repo_gpgcheck=1 # 저장소 메타데이터(repomd.xml) 서명 검증
enabled=1
gpgcheck=1 # 개별 RPM 패키지 서명 검증
gpgkey=https://rpm.grafana.com/gpg.key
| 옵션 | 검증 대상 | 설명 |
|---|---|---|
gpgcheck=1 | 개별 .rpm 파일 | 다운로드한 RPM 패키지 자체의 GPG 서명을 검증합니다 |
repo_gpgcheck=1 | 저장소 메타데이터 | repomd.xml 등 저장소 인덱스 파일의 GPG 서명을 검증합니다 |
gpgcheck만 활성화하면 개별 패키지의 무결성은 보장되지만, 저장소 자체가 변조되어 악성 패키지 목록을 내려주는 중간자 공격(MITM)에는 취약할 수 있습니다. 프로덕션 환경에서는 둘 다 활성화하는 것이 권장됩니다.
RPM(Red Hat Package Manager)은 Red Hat 계열 Linux 배포판(RHEL, CentOS, Fedora, Rocky Linux 등)에서 소프트웨어를 패키징, 설치, 업데이트, 삭제, 검증하기 위한 패키지 관리 시스템입니다.
.rpm 확장자를 가진 패키지 파일을 다루며, 패키지의 메타데이터(이름, 버전, 의존성 등)와 실제 파일들을 하나의 아카이브로 묶어 관리합니다. Debian 계열의 .deb에 대응하는 개념이라고 생각하시면 됩니다.
Node.js 개발자에게 익숙한 npm으로 비유하면 다음과 같습니다:
| npm 생태계 | RPM 생태계 | 역할 |
|---|---|---|
.tgz (패키지 파일) | .rpm (패키지 파일) | 소프트웨어를 담은 아카이브 |
npm | rpm | 저수준 패키지 설치/삭제 (의존성 직접 해결 안 됨) |
npx / npm install | yum / dnf | 의존성 자동 해결 + 설치 |
npmjs.com (레지스트리) | /etc/yum.repos.d/ (원격 저장소) | 패키지를 가져오는 출처 |
package.json | RPM .spec 파일 | 패키지 메타데이터 (이름, 버전, 의존성) |
즉, npm install express 하면 npm이 의존성을 알아서 해결하듯, dnf install alloy 하면 dnf가 의존성을 자동으로 해결해줍니다. rpm만 단독으로 쓰면 의존성을 직접 하나하나 설치해야 하는 점이, .tgz 파일을 수동으로 풀어 설치하는 것과 비슷합니다.
# RPM 기본 명령어 예시
rpm -i package.rpm # 설치 (install)
rpm -U package.rpm # 업그레이드 (upgrade), 없으면 설치
rpm -e package-name # 삭제 (erase)
rpm -q package-name # 설치 여부 조회 (query)
rpm -qa # 설치된 모든 패키지 목록 조회
.rpm 파일은 4개의 논리적 섹션으로 구성됩니다.
┌─────────────────────────────────────────────┐
│ Lead (96 bytes) │
│ 매직 넘버: 0xED 0xAB 0xEE 0xDB │
│ → RPM 파일임을 식별하는 고정 헤더 │
├─────────────────────────────────────────────┤
│ Signature │
│ → 패키지의 무결성과 출처를 검증하는 │
│ 디지털 서명 (GPG 서명 포함) │
├─────────────────────────────────────────────┤
│ Header │
│ → 패키지 메타데이터 │
│ (이름, 버전, 의존성, 파일 목록 등) │
├─────────────────────────────────────────────┤
│ Payload │
│ → 실제 설치 파일들의 압축 아카이브 │
│ (cpio + gzip 형식) │
└─────────────────────────────────────────────┘
| 섹션 | 역할 |
|---|---|
| Lead | 매직 넘버(0xEDABEEDB)로 RPM 파일 식별. 패키지 타입, 아키텍처 등 기본 정보 포함 |
| Signature | MD5, SHA256 다이제스트와 GPG 서명을 포함. 패키지 변조 여부를 검증하는 핵심 영역 |
| Header | 패키지 이름, 버전, 의존성 목록, 설치될 파일 경로, pre/post 설치 스크립트 등 모든 메타데이터 |
| Payload | SVR4 cpio 아카이브를 gzip으로 압축한 실제 파일 데이터 |
GPG 서명은 Signature 섹션에 저장됩니다. rpm -K 명령어로 패키지를 검증할 때, RPM은 이 Signature 섹션에 포함된 GPG 서명을 읽어 Header와 Payload가 변조되지 않았는지 확인합니다.
rpm --import패키지의 GPG 서명을 검증하려면, 먼저 배포자의 공개 키를 시스템 RPM 키링에 등록해야 합니다.
# URL에서 직접 가져와 등록
sudo rpm --import https://rpm.grafana.com/gpg.key
# 또는 로컬 파일로 등록
wget -q -O gpg.key https://rpm.grafana.com/gpg.key
sudo rpm --import gpg.key
등록된 키는 RPM 데이터베이스에 gpg-pubkey라는 이름의 패키지처럼 저장됩니다. 따라서 일반 패키지와 동일한 방식으로 조회하고 삭제할 수 있습니다.
# 등록된 모든 GPG 공개 키 목록 조회
rpm -qa gpg-pubkey*
# 특정 키의 상세 정보 확인
rpm -qi gpg-pubkey-4e40dba8-6572e917
# 키 삭제 (필요 시)
sudo rpm -e gpg-pubkey-4e40dba8-6572e917
rpm -K다운로드한 .rpm 파일의 서명을 수동으로 검증할 수 있습니다.
rpm -K alloy-1.8.1-1.amd64.rpm
| 출력 키워드 | 의미 | 조치 |
|---|---|---|
digests signatures OK | 다이제스트와 서명 모두 검증 성공 | 안전하게 설치 가능 |
NOKEY | 서명 검증에 필요한 공개 키가 시스템에 없음 | rpm --import로 키 등록 후 재검증 |
NOT OK | 서명 검증 실패 (패키지 변조 가능성) | 해당 패키지를 신뢰하지 말 것 |
| 명령어 | 용도 |
|---|---|
rpm --import <key-url> | GPG 공개 키를 RPM 키링에 등록 |
rpm -K <package.rpm> | 패키지의 서명과 다이제스트 검증 |
rpm -qa gpg-pubkey* | 등록된 GPG 키 목록 조회 |
rpm -qi gpg-pubkey-<id> | 특정 GPG 키 상세 정보 확인 |
rpm -e gpg-pubkey-<id> | 등록된 GPG 키 삭제 |
RPM은 단일 패키지를 다루는 저수준 도구입니다. 패키지 A가 B에 의존하고, B가 다시 C에 의존한다면, RPM만으로는 사용자가 직접 B와 C를 먼저 찾아 설치해야 합니다.
이 문제를 해결하기 위해 RPM 위에 yum(Yellowdog Updater Modified)과 그 후속 도구인 dnf(Dandified YUM)가 만들어졌습니다.
┌──────────────────────────────────────────┐
│ 사용자 │
│ $ dnf install alloy │
└──────────┬───────────────────────────────┘
│
┌──────────▼───────────────────────────────┐
│ dnf / yum (고수준 패키지 관리자) │
│ ① 원격 저장소에서 메타데이터 다운로드 │
│ ② 의존성 트리 계산 (SAT Solver) │
│ ③ repo_gpgcheck: 메타데이터 서명 검증 │
│ ④ 필요한 .rpm 파일들 다운로드 │
│ ⑤ gpgcheck: 개별 .rpm 파일 서명 검증 │
└──────────┬───────────────────────────────┘
│
┌──────────▼───────────────────────────────┐
│ RPM (저수준 패키지 관리자) │
│ ⑥ .rpm 파일 언패킹 및 설치 │
│ ⑦ RPM 데이터베이스에 설치 정보 기록 │
│ ⑧ pre/post 설치 스크립트 실행 │
└──────────────────────────────────────────┘
| 구분 | RPM | yum | dnf |
|---|---|---|---|
| 역할 | 단일 패키지 설치/삭제/조회 | RPM 위의 고수준 패키지 관리 | yum의 차세대 버전 |
| 의존성 해결 | 불가 (수동 해결 필요) | 자체 의존성 해결 엔진 | libsolv 기반 SAT Solver |
| 저장소 관리 | 불가 | /etc/yum.repos.d/ 기반 | /etc/yum.repos.d/ 기반 |
| GPG 검증 | rpm -K로 수동 검증 | gpgcheck, repo_gpgcheck 자동 검증 | 동일 |
정리하면,
dnf install alloy명령 한 줄 뒤에서는 dnf가 저장소 메타데이터 검증 → 의존성 계산 → 패키지 다운로드 → GPG 서명 검증을 수행하고, 최종적으로 RPM을 호출하여 실제 설치를 진행합니다.
문제 발생 시 아래 순서로 확인하면 대부분의 GPG 관련 이슈를 해결할 수 있습니다.
# 1. 현재 등록된 GPG 키 목록 확인
rpm -qa gpg-pubkey* --qf '%{NAME}-%{VERSION}-%{RELEASE} → %{SUMMARY}\n'
# 2. 저장소 설정 파일 확인
cat /etc/yum.repos.d/grafana.repo
# 3. 공개 키 내용(핑거프린트, 만료일) 확인
curl -sL https://rpm.grafana.com/gpg.key | gpg --show-keys
# 4. dnf 캐시 전체 초기화
sudo dnf clean all
# 5. 키 재등록 후 재시도
sudo rpm --import https://rpm.grafana.com/gpg.key
sudo dnf install alloy
주의:
gpgcheck=0으로 설정하여 패키지 서명 검증 자체를 비활성화하는 것은 프로덕션 환경에서 심각한 보안 위험을 초래합니다. 반드시 근본 원인을 파악하고 해결해야 합니다.
Elastic Beanstalk 인스턴스에 Grafana Alloy를 설치하는 쉘 스크립트(predeploy hook)에서 GPG 인증에 실패하여 배포가 중단되었습니다.
원본 스크립트는 다음과 같은 흐름이었습니다:
# 1. Grafana 공식 저장소에서 GPG 키 다운로드 및 import
wget -q -O /tmp/gpg.key https://rpm.grafana.com/gpg.key && sudo rpm --import /tmp/gpg.key
# 2. Grafana 저장소 등록 (gpgcheck=1, repo_gpgcheck=1)
# 3. yum install -y alloy
GPG 인증 실패는 단일 원인이 아니라, 여러 문제가 연쇄적으로 발생한 결과였습니다.
wget -q -O /tmp/gpg.key https://rpm.grafana.com/gpg.key
# → 실패: EB 인스턴스에서 rpm.grafana.com에 접근 불가
네트워크 정책에 따라 일부 외부 저장소에 대한 아웃바운드 접근이 제한되는 환경이었습니다.
반면 내부에서 관리하는 아티팩트 저장소는 정상적으로 접근이 가능했습니다.
GPG 키가 import되지 않았으므로, 이후 repo_gpgcheck와 gpgcheck 모두 실패하는 연쇄 반응이 발생했습니다.
GPG 키 다운로드 소스를 S3/CloudFront로 변경했지만, 이번에는 키 불일치 문제가 발생했습니다.
# import된 키: S3/CF에 올려둔 키
rpm --import /tmp/gpg.key
# repo 설정의 gpgkey: Grafana 공식 키
gpgkey=https://rpm.grafana.com/gpg.key # ← 여전히 Grafana 공식 URL
S3/CF에 미러링된 GPG 키와 Grafana 공식 저장소의 RPM 패키지 서명 키가 서로 달랐습니다. Grafana 공식 저장소에서 다운로드한 패키지를 S3/CF 키로 검증하려 하니 당연히 실패했습니다.
repo_gpgcheck=0, gpgcheck=0으로 모두 비활성화한 후 yum install -y alloy를 시도했으나, yum이 Grafana 저장소 전체 메타데이터를 다운로드하고 의존성을 해석하는 과정에서 OOM(메모리 부족)이 발생했습니다. 해당 인스턴스가 t3.micro (메모리 1GB)로 운영되고 있어, yum 메타데이터 처리를 감당할 수 없었습니다.
| 단계 | 문제 | 원인 |
|---|---|---|
| GPG 키 다운로드 | rpm.grafana.com 접근 실패 | EB 인스턴스 VPC 네트워크 제한 |
repo_gpgcheck=1 | 저장소 메타데이터 서명 검증 실패 | GPG 키 미 import (위 실패의 연쇄) |
gpgcheck=1 | 패키지 서명 검증 실패 | S3/CF 키 ≠ Grafana 공식 패키지 서명 키 |
yum install | OOM | 저사양 인스턴스(1GB 메모리)에서 yum 메타데이터 처리 불가 |
GPG 문제와 OOM 문제가 별개로 존재해서, yum 저장소 방식 자체를 포기하고 다음과 같이 전환했습니다.
| 항목 | yum install (저장소 방식) | yum localinstall (로컬 방식) |
|---|---|---|
| 메타데이터 다운로드 | 저장소 전체 메타데이터를 메모리에 로드 | 없음 (로컬 파일만 읽음) |
| 의존성 해석 | 저장소 전체 패키지 목록에서 계산 | 로컬 RPM의 의존성만 확인 |
| 메모리 사용량 | 높음 (저장소 규모에 비례) | 낮음 |
| 네트워크 의존성 | 저장소 접근 필수 | 없음 (이미 다운로드 완료) |
| GPG 검증 | gpgcheck + repo_gpgcheck | localpkg_gpgcheck만 해당 |
| 설치 속도 | 느림 (메타데이터 동기화 + 다운로드) | 빠름 (바로 설치) |
t3.micro처럼 메모리가 제한된 환경에서는 yum이 저장소 메타데이터를 메모리에 올리는 것만으로도 OOM이 발생할 수 있습니다. localinstall은 이 과정을 완전히 건너뛰기 때문에, 저사양 인스턴스에서도 안정적으로 설치할 수 있습니다.
사전 검증된 RPM
↓ S3 업로드
S3
├── /product/install/gpg.key ← GPG 키
├── /product/versions/latest.txt ← 최신 버전 정보
└── /product/install/packages/*.rpm ← RPM 패키지
↓ curl 직접 다운로드
EB 인스턴스
↓ yum localinstall (localpkg_gpgcheck=0)
product 설치 완료
# GPG 키 다운로드 및 import
curl -fsSLo /tmp/gpg.key https://{s3}/product/install/gpg.key \
&& rpm --import /tmp/gpg.key
# RPM 직접 다운로드
curl -fsSLo /tmp/product.rpm https://{s3}/product/install/packages/product-x.x.x.rpm
# localinstall로 설치
yum -y --setopt=localpkg_gpgcheck=<org_policy> localinstall /tmp/product.rpm
패키지는 사내 배포 파이프라인에서 무결성과 출처를 사전 검증한 뒤 내부 저장소에 배포하는 방식으로 전환했습니다.
인스턴스에서는 내부 정책에 맞춰 설치 단계를 단순화하여, 제한된 리소스 환경에서도 안정적으로 설치되도록 구성했습니다.
| 원인 | 결과 |
|---|---|
VPC 네트워크 제한으로 rpm.grafana.com 접근 불가 | GPG 키 다운로드 실패 → 서명 검증 전체 실패 |
| S3/CF 키와 Grafana 공식 패키지 서명 키 불일치 | gpgcheck=1 검증 실패 |
| t3.micro(1GB)에서 yum 저장소 메타데이터 처리 | OOM 발생 |
yum install → yum localinstall로 전환 | 메타데이터 로드 제거로 OOM 해소, 네트워크 의존성 제거 |
| 이미 인증된 패키지를 S3에서 관리 | localpkg_gpgcheck=0으로 GPG 재검증 불필요 |