19.8 파이프라인 내 설정 및 보안/인증 관리
이전 장들에서는 소스 코드를 빌드하고 최적화하여 런타임 환경에 안전하게 전달하는 시스템 관점의 배포 파이프라인 인프라 구축에 대해 살펴보았다. 그러나 물리적으로 완벽한 파이프라인이라 할지라도, 시스템과 디바이스 간의 신뢰를 담보하는 ’보안 인증서(Certificate)’와 ’접근 자격 증명(Credentials)’의 관리 절차가 소홀하다면 시스템의 보안 안정성은 심각한 위협에 노출될 수 있다.
배포 및 형상 관리 시스템에서 가장 많이 발생하는 취약점 중 하나는 바로 환경 변수 구성 파일, 데이터베이스 접근 권한 정보, 혹은 TLS 인증서 파일이 암호화 없이(Plain-Text) 소스 코드와 함께 Git 저장소에 하드코딩되어 병합되는 실수이다.
graph LR
subgraph "권장되지 않는 관리 방식 (하드코딩 취약 패러다임)"
Developer[개발 환경 제공자] -->|Credentials 내장 변경안 병합| Git[Git Repository]
Git -->|취약점 노출 위험 관리| Hacker[비정상 접근 및 탈취 리스크]
end
subgraph "모던 DevSecOps 파이프라인 모델 (Secret Management)"
Pipe[CI/CD Pipeline] -->|동적 인증 발급 연계 요청| Vault[(Secure Vault)]
Vault -->|보안 암호화 키 등 임시 발급| Pipe
Pipe -->|격리된 임시 가상 메모리를 통한 전승| Prod[Production Zenoh Node]
end
이 단원에서는 배포 파이프라인의 생명 주기 내부에서 필수적으로 다루어지는 환경 인자(Environment Configuration) 및 보안 인증 주체(TLS/SSL/Token)들을 기계적으로 안전하게 관리하는 방안에 대해 학습한다. 시스템 인증 요소가 형상 관리 시스템에 평문으로 남지 않도록 암호화하여 격리 보관(Isolation)하고, 인스턴스 부팅 단계에서 동적으로 주입(Dynamic Injection)시키는 고도화된 소프트웨어 보안 통합(DevSecOps) 철학의 근간을 구축할 것이다.
1. K8s Secrets 및 HashiCorp Vault를 활용한 Zenoh 인증서(TLS/SSL) 자동 주입
도커 컨테이너 이미지(zenoh-router:v1) 내부에는 절대로 암호가 들어있어선 안 된다. 컨테이너는 오직 순수한 컨테이너 이미지여야 한다.
1.0.1 [인스펙션] 금고 연동(Vault Injection) 전술
비밀번호는 컨테이너가 켜지는 첫 1초에만 존재해야 한다.
1. K8s Secrets 볼륨 마운트
인프라 관리자가 쿠버네티스 마스터에 tls-secret 이라는 이름으로 인증서 파일을 밀어 넣는다(Base64 인코딩).
Zenoh 라우터 파드 YAML 에는 코드가 아닌 volumeMounts 를 갈아 끼운다. K8s 가 파드를 실행할 때, 이 시크릿을 가로채어 파드 내부의 /etc/zenoh/ssl/ 폴더에 “가짜 파일” 처럼 연결한다. 코드는 그저 로컬 파일을 읽을 뿐이지만, 이 공간은 RAM 디스크 위를 떠다니는 완전한 보안 영역이다.
2. HashiCorp Vault 의 동적 인증서 발급
K8s 시크릿은 여전히 K8s 관리자에게 노출될 위험이 있다.
궁극의 보안은 HashiCorp Vault Agent 를 Zenoh 파드 옆에 사이드카(Sidecar) 로 붙이는 것이다. 라우터가 부팅될 때, 이 사이드카가 중앙 금고(Vault) 와 텔레파시를 주고받아 1개월짜리 “단기 TLS 인증서” 를 실시간으로 발급받아 메모리에 적어준다. 1개월 뒤에는 파드 재시동 없이 사이드카가 스스로 새 인증서를 갱신해 버리는 완벽한 Zero-Trust 오토메이션의 완성이다.
2. 환경별 설정의 분리와 동적 주입 (Configuration Management)
스마트 설비 혹은 글로벌 디바이스 네트워크를 구축할 때 겪게 되는 핵심 난관은, 개발 환경 스펙(Local), 검증 단계(QA), 그리고 실제 운영 단계(Production)의 물리적 주소 체계와 DB 구성 등 시스템 변수가 상이하다는 점에 있다. 서로 다른 파라미터나 환경 변수를 단일 코드 내의 하드 코딩 및 조건 분기문(if-else)으로 대응하게 되면 향후 막대한 기술 부채와 변경 지연을 초래하게 된다.
모던 클라우드 네이티브 개발 지침인 The Twelve-Factor App 원칙에 따르면, 배포를 위한 아키텍처 바이너리(Image)는 어느 환경에서도 동일하게 배포되어야 하며, 변경되는 설정 변수(Config)는 오직 인프라 파이프라인이 런타임에 동적으로 주입해야 함을 강조한다.
2.1 코드 자원과 설정(Configure) 자원의 분리 전술 모델
가동 환경을 대비해 빌드된 Zenoh 컨테이너 패키지는 환경 정보를 소유하지 않는다. 하지만 쿠버네티스(K8s) 상으로 기동되는 연결 프로세스 시, 외부 통제 라인으로부터 환경 인자 정보들이 주입된다.
2.1.1 단계: K8s ConfigMap 적용을 통한 환경의 격리 배치
배포할 각 클러스터의 환경 변수 관리 정보(설정)를 개별 매니페스트 ConfigMap 이라는 별개의 분리된 K8s 객체 안에 선언한다.
## zenoh-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: zenoh-env-config
data:
# 배포 환경 목적지 명칭
ENVIRONMENT: "production-zone-A"
# Zenoh 인스턴스가 라우팅될 네트워크 노드의 목적 엔드포인트
CORE_ROUTER_ENDPOINT: "tcp/nlb-eu-west-1.zenoh.io:7447"
# 해당 환경에서의 상세 로깅 레벨 할당
ZENOH_LOG_LEVEL: "info"
2.1.2 단계: 컨테이너 런타임 주입 바인딩
이제 K8s 파드 스펙(Pod Spec)에서 내부 환경 정보를 참조할 때, 별도로 정의된 바인딩 레퍼런스(envFrom) 관문을 파드 구성에 기입한다.
## 배포 파드 명세 내부
spec:
containers:
- name: zenoh-robotics-client
image: enterprise/zenoh-client:v1.3
# ConfigMap 내에 선언된 매핑 쌍 정보를 모두 프로세스의
# 환경변수 값(Env)으로 프로세스 시스템에 직접 치환 공급
envFrom:
- configMapRef:
name: zenoh-env-config
상기한 주입 원리에 의해 컨테이너 자체 Zenoh 코딩 내에서는 OS 환경 변수 리딩, 예로서 os.getenv("CORE_ROUTER_ENDPOINT") 혹은 env::var()의 형식으로 호출하기만 해도 어플리케이션이 정상적으로 위치 정보를 파악, 유연한 동작을 발휘한다.
2.1.3 단계: CI/CD 파이프라인 스택의 변수 전달
그렇다면 특정 배포 단계별로 해당 ConfigMap 리소스 매니페스트를 모두 독립적으로 관리해야 될까? 그것은 아니다.
배포 엔진 파이프라인(Helm 등 매니페스트 관리 도구) 내에서 설정 변수를 템플릿(Template)화하고 변수 영역 치환 원리를 통해 해당 배포 명령 간 자동으로 적용해야 한다.
## GitLab CI 파이프라인 변환 적용 예시 커맨드 구조
deploy_region_A:
script:
# 파이프라인 실행 시 받아오는 지역 변수 인수 정보 $TARGET_ENV
# 해당 값으로 변수 치환 후 헬름(Helm) 업그레이드 전개
- helm upgrade --install zenoh-app ./chart --set env.region=$TARGET_ENV
이와 같은 추상화 구조 분리 패턴을 구축하면, 소스 레벨의 컨테이너 이미지 산출물(Artifact)은 완전히 동결 보존이 가능해지며, 개별 실행 시스템이나 국가별 환경 변수가 무엇이든 오직 외부에 구성된 변수 관리를 통해 배포 확장성 및 무결성이 입증된 완벽한 설정 분리 아키텍처망을 갖추게 된다.
3. TLS 인증서 및 접근 토큰의 안전한 보관과 자동화된 갱신(Vault 연동)
Zenoh 통신 모델을 실 환경 운영할 때, 네트워크 스니핑이나 위변조를 막기 위해 TLS(Transport Layer Security) 암호화와 접근 자격 토큰(Access Token 등)을 요구하게 된다.
만성적으로 많이 범해지는 보안 아키텍처의 빈틈은 인증서 물리 파일(.pem, .crt 등)을 직접 운영 장비의 /etc/zenoh/ 레벨 디렉토리 경로에 설치 이미지나 볼륨으로 저장해 두는 것이다. 이는 외부 노출 및 인증 정보의 도난 위험성이 매우 크다.
신뢰성에 직결되는 보안 체계(Secret)의 증서나 자격 증명은 단일의 파일 구조를 가지는 것이 아닌 유기적인 유효기간을 제어받으며, 디스크 영역이 아닌 오직 휘발성 가상 메모리(RAM) 위에서 존재하다 제거되는 갱신 라이프사이클을 배포 파이프라인 단위에서 일원 관리하는 형태여야 함을 시사한다.
3.1 중앙 집중형 인프라 Secret 관리 연동 기전
시스템적 보안의 권한 분산을 달성하기 위해서, 개발자나 파이프라인 인프라 운영자가 비밀 정보를 수동으로 제어하지 않는 HashiCorp Vault와 K8s 컴포넌트를 통합 구성하는 매커니즘을 연계한다.
3.1.1 단계: K8s Secrets 객체와 파이프라인 연동성
기반 단계로서 CI 봇 파이프라인 시스템은 컴파일이나 배포 단계 시 별도 권한을 통과 후 임시 키를 획득하는 구조를 통하여 K8s 자체 시크릿(Secret) 객체 보관 공간에 자원을 발급해 넣어야 한다.
## 자동화 봇 시스템이나 Jenkins 등을 통해 Vault로부터
## 발급받은 임시 증명 파일을 K8s 보안 자산 공간인 secret에 탑재
kubectl create secret generic zenoh-tls-secret \
--from-file=tls.key=./device-private-key.pem \
--from-file=tls.crt=./device-cert.pem \
--namespace zenoh-system
3.1.2 단계: 임시 가상 메모리를 통한 보안 자산 접근 제어 (In-Memory Volume)
Zenoh가 컨테이너 구성에서 프로세스로 작동될 때, 해당 인증 모듈을 사용해야만 한다면 어플리케이션 자체의 포맷이나 바이너리, 그리고 OS 환경 환경 변수(env) 변환으로 이를 치환해서 탑재하면 취약점이 심각하게 수반된다. (서버 크래시 분석 시 노출 우려 높음)
이 같은 위험을 제로 베이스로 만들기 위해 K8s의 메모리 마운트 방식은 tmpfs 라는 임시 파일 시스템 메모리 공간 기반 볼륨을 생성 및 제공한다.
## Zenoh 구동 매니페스트 보안 구성 스펙
spec:
containers:
- name: zenoh-router
volumeMounts:
- name: tls-certs-volume
mountPath: /etc/zenoh/certs # 애플리케이션에서는 실제 디렉토리로 참조
readOnly: true
volumes:
- name: tls-certs-volume
secret:
secretName: zenoh-tls-secret # 메모리 캐시 기반 참조
이를 통해 파드의 역할 생명주기가 종료, 크래시 발생 혹은 삭제되었을 때 해당 TLS 파일 증명 캐시들은 물리적인 디스크가 아닌 메모리 영역에 종속되어 완전하게 즉시 휘발 처리되므로 외부 침투 요소에 분석되지 않는 강경한 보호 계층을 구축한다.
3.1.3 단계: 인증 모듈 갱신 주기의 완전한 자동화 시스템 도입
보안 정책상 시스템의 자격 증명서 기간은 한정성을 띠며 일정 기간 내 기계적 갱신이 필요하다.
이를 위해 쿠버네티스의 cert-manager 컴포넌트를 적용한다. cert-manager가 환경 내에서 구동됨으로써, 인증 연한 만료 일정일 전 Vault나 Let’s Encrypt 백엔드와 오토 연계, 신규 Key와 Crt 인증 라이센스를 발급받은 뒤 기존 K8s의 Secret 데이터를 교대(Swapping)해 준다.
비밀 키 교체가 K8s 상에 발생 시 파드 구성 파일 변경을 관측 처리하여 낡은 TLS 키가 포함된 라우터들의 파드를 자동 재부팅 및 신규 세션 스웜화 시킴으로써 전 기간에 걸쳐 영구적인 최신 안전 통신 상태를 지속 확보할 수 있게 된다.
4. 에지와 클라우드 등 배포 대상 환경에 따른 동적 설정(Configuration) 파일 분리 및 주입
“개발 환경(Dev) 의 Zenoh 는 디버그 로그(RUST_LOG=debug) 를 뿜고, 운영 환경(Prod) 의 Zenoh 는 경고 로그(error) 만 뿜게 해라.”
코드를 2번 짤 것인가? 도커 이미지를 2개 만들 것인가? 둘 다 죄악이다.
4.0.1 [Runbook] 카멜레온(Chameleon) 바인딩 런북
이미지는 하나(One Image), 설정은 백 개(Any Config)
1. ConfigMap 기반의 주입
쿠버네티스의 ConfigMap 은 코드를 수정하지 않고 심성을 바꾸는 최면술이다.
zenoh-config-dev 와 zenoh-config-prod 를 별도로 구워둔 뒤, Helm 배포 파이프라인에서
envFrom:
- configMapRef:
name: "{{ .Values.configName }}"
이라는 템플릿 변수를 뚫어둔다. CI/CD 파이프라인이 Dev 클러스터로 배포할 때는 파드에 Dev 설정 뭉치를 먹이고, Prod 로 넘길 때는 Prod 설정 뭉치를 먹여 컨테이너의 성격(Log level, Ports) 을 찰나의 순간에 변이시켜라.
2. 환경 변수 오버라이드 (Environment Variable Override)
가장 무식하지만 가장 확실한 방법이다. zenoh.json 에는 listen: "tcp/${ZENOH_LISTEN_IP}:7447" 처럼 자리표시자를 만들어두고, 도커 컨테이너가 켜지는 순간(ENTRYPOINT) 에 envsubst 리눅스 명령어가 이 텍스트를 파고들어 진짜 IP 로 치환한 뒤 데몬을 띄우게 만들면 어떠한 배포 환경에서도 살아남는 만능 도커 이미지가 완성된다.
5. CI/CD 파이프라인 자체의 역할 기반 접근 제어(RBAC) 및 배포 감사 로깅(Audit Logging)
개발자가 코드를 짜는 건 자유지만, ‘운영망 반영(Prod Deploy)’ 버튼을 누르는 건 권력이다. 누군가 악상을 품고 공장 전체 네트워크를 파괴하는 코드를 강제 병합(Force Merge) 해버린다면 어떻게 막을 것인가?
5.0.1 [인스펙션] 판옵티콘(Panopticon) 통제 전술
파이프라인 버튼에도 신분증(ID) 을 검사한다.
1. 워크플로우 4단계 결재선(Approval Gate) 활성화
GitHub Actions 의 Environments 기능이나 GitLab 의 Protected Environments 를 가동하라.
코드 빌드(CI) 는 누구나 할 수 있지만, job: deploy-to-prod 스텝이 켜지는 순간 파이프라인은 정지(Wait) 하고 팀장 혹은 시니어 엔지니어 2명 이상의 슬랙으로 알람을 때린다. 이들이 코드를 확인하고 승인(Approve) 버튼을 누리기 전까지는 죽어도 배포 스크립트가 돌아가지 않는 완벽한 에어갭(Air-gap) 을 건설해야 한다.
2. GitOps 배포 원장(Audit Trail) 불변 보존
“누가 어제 새벽 2시에 드론 펌웨어를 리모컨으로 날렸어!”
추궁할 필요가 없다. GitOps(ArgoCD) 체제에서는 서버에 누가 SSH 로 들어간 흔적을 쫓지 않는다. 무조건 GitHub Deploy Repository 의 커밋 이력을 까보면 된다.
JIRA-8123: Update drone firmware to v2.3 - by Mike 라는 영원히 삭제 불가능한 Git 커밋 기록 자체가 모든 인프라 변경의 법적/기술적 감사 로그(Audit Log) 로 동작하는 무결성의 위엄을 체감하라.
6. 파이프라인 자체의 Role-Based Access Control(RBAC) 및 감사 로그(Audit)
앞서 구축된 클라우드 파이프라인 시스템과 에지 로봇 군단이 안전한 시크릿 방어체계를 갖추었지만, 이 모든 자동화의 통제를 전담하는 도구, 즉 젠킨스(Jenkins), GitHub Actions, 또는 깃옵스 앵커 컨트롤 도구(ArgoCD) 인프라 자체의 권한 관리가 취약하다면 더 큰 위협이 야기될 수 있다.
배포 자동화를 관장하는 주체 시스템의 무제한적 권한 탈취는 분산 망 전체 시스템을 위협할 수 있다. 그렇기에 우리는 시스템을 구축함과 동시에 배포 파이프라인 에이전트들의 시스템 아이덴티티(Identity) 및 권한(Authorization)을 극도로 제한하고 분리하는 RBAC (Role-Based Access Control) 구조와 철저하게 분리된 로그 추적(Audit Trail) 시스템을 반드시 포함해야 한다.
6.1 최소 권한 원칙 부여 (Principle of Least Privilege)
CI/CD 파이프라인 봇 에이전트 하나에 거대한 클라우드 자원을 모두 운영할 수 있는 최고 관리자 토큰권(AdministratorAccess)을 부여하는 것은 전형적인 최악의 보안 오탐(Misconfiguration) 패턴이며 대단히 위험한 행위이다.
- 조각난 위임 프로세스 설계 요소:
GitHub Actions의 CI 시스템은 어플리케이션 빌드를 통해 산출 이미지 패키지를 도커 컨테이너 레지스트리에 푸시할 수 있는 권한(PushOnly)만을 제공한다.
해당 빌드를 탐지하여 배포를 일임받는 ArgoCD 컴포넌트에는 배포 환경 Git 저장소를 단순히 감시할 수 있는ReadOnly데이터 허가만을 부여하고, 실제 프로덕션 배치에서는 오직 특정 구역으로 명명된 쿠버네티스의 타겟팅 네임스페이스 영역 안에서만 컨테이너 객체를 전개할 수 있는 제한된 매니페스트 실행 규격을 체계적으로 지정하라.
## K8s 배포 봇에 대한 권한 제어 요소(RBAC Role) 작성
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: zenoh-prod
name: zenoh-deployer-role
rules:
- apiGroups: ["apps", ""] # K8s 기본 내장 컴포넌트 리소스 조작
# 시크릿(Secret) 토큰 영역은 불가, 오직 배포 요소의 컴포넌트들에만 전개 권한 일임
resources: ["deployments", "pods", "services", "configmaps"]
verbs: ["get", "list", "watch", "create", "update", "patch"]
6.1.1 OIDC (OpenID Connect) 인증 시스템 연동: 무기한 접근 토큰의 대안 설계
파이프라인 서버 시스템이 AWS 등의 외부 클라우드 리소스 및 스토리지 공간에 접근 필요성이 발생할 시, 시스템 환경 변수에 반영구적(Long-term) 정적 엑세스 키(Access Key)를 하드 파싱하여 부여하면 안 된다.
보다 안전한 통제 대안을 위해 OIDC(OpenID Connect)의 메커니즘을 파이프라인 인가 시스템에 연계한다.
해당 시스템을 구축하면, AWS IAM(Identity and Access Management) 기능은 외부 인증 절차의 검사를 요청, 오직 인가된 주요 코드 저장소의 주축 브랜치 이벤트 등 엄밀한 한정적 시간, 런타임 제약 조건을 달고 있는 상태에서 한시적으로 존속(10분 등)되는 동기적인 임시 엑세스 발급 키(Short-term Credential)만을 파이프라인 엔진으로 발송한다. 이후 해당 빌드 스텝 종료 즉시 해당 보안 토큰의 소유권은 소멸되므로 만성적인 클라우드 패스워드 및 스펙 키 유출 재앙 리스크를 본질적으로 회피하는 아키텍처망이 도입되는 효과를 보장한다.
6.2 디지털 감사 로그 체계의 안전한 분리 추적
시스템의 대형 아키텍처 장애나 이슈가 야기될 경우, 문제 발생의 최초 시점과 관련된 주체를 검증하는 것이 원인 분석의 핵심이다.
이러한 목적을 달성하기 위해 모든 배포 앵커 도구 시스템들의 기록 인자 모델은 운영 시스템 외부에 별개로 독립되어 있는 모니터링 로그 집적소나 클라우드 기반 감사 매니지드 엔진 플랫폼(Datadog, AWS CloudTrail 등 조작이 불가능한 구조의 폴더) 영역으로 실시간 통합 수집되어 보존(Retention)되어야 한다.
안정적인 에지/클라우드의 진보적 관제 팀 조직은 인간 개발자의 구두 기억 인자나 엑셀 등 외부 수기 요소를 신뢰할 것이 아니라, 결코 조작 불가능함을 지향하는 시스템적 객체 로그 체인으로 구성된 **분명한 이중 감사 타임스탬프 정보(Audit Record log)**만을 토대로 전체 배포 파이프라인 상의 통로 결함을 추적한다. 이러한 관점의 투명한 감사 시스템 확보는 진보된 파이프라인이 제공해야 할 완전한 통제 시스템 아키텍처의 철학이며 실사례일 것이다.