제13부 보안
13.3 DDS-Security 플러그인 상세
13.3.1 이 장에서 배우는 것 / 선수 지식
13.2에서 SROS 2를 도구로 다뤘다. 이 장은 그 아래 — 실제로 인증하고 암호화하는 메커니즘이다.
이 층을 알아야 하는 이유는 세 가지다. 첫째, SROS 2가 만드는 파일들이 무엇을 의미하는지 알아야 정책을 제대로 쓸 수 있다. 둘째, 성능 비용이 어디서 발생하는지(13.5) 이해하려면 무엇이 암호화되는지 알아야 한다. 셋째, 문제가 생겼을 때 어느 층인지 구분해야 한다.
배우는 것:
- 플러그인 구조 — 다섯 가지 서비스 플러그인.
- 인증 — 신원 확인 과정.
- 접근 제어 — 권한서와 거버넌스.
- 암호화 — 무엇이 어떻게 보호되는가.
- 보호 수준 — 선택지와 의미.
- 디스커버리 보호 — 놓치기 쉬운 부분.
- 구현별 차이 — 정직한 확인 사항.
선수 지식: 13.2(SROS 2), 3.1~3.3(DDS·RTPS·디스커버리), 3.5(RMW 구현).
정직: 거버넌스 파일의 실물과 스키마는 Jazzy에서 직접 생성·확인했다(실행 확인 — 13.3.11). 구현별 지원 범위·성숙도는 여전히 다르며, 벤더별 설정 방법은 확인하지 않았다. 여기서는 표준의 개념 구조를 다루며, 실제 사용은 선택한 RMW·DDS 구현의 문서를 따라야 한다. 암호 알고리즘·키 길이 등 구체적 선택은 조직의 보안 정책과 전문가 판단의 영역이며, 이 책은 그에 관한 조언을 제공하지 않는다. 성능 수치는 제시하지 않는다(3.6.1). 이 환경에서 검증하지 않았다(목차 3).
13.3.2 플러그인 구조
DDS-Security는 다섯 가지 서비스 플러그인으로 정의된다.
| 플러그인 | 역할 | SROS 2와의 관계 |
|---|---|---|
| ① 인증 | 참여자가 누구인가 | 신원 인증서 |
| ② 접근 제어 | 무엇을 할 수 있는가 | 권한서·거버넌스 |
| ③ 암호 | 기밀성·무결성 | 보호 수준 설정 |
| ④ 로깅 | 보안 이벤트 기록 | SROS 2가 생성하는 설정에 없다(실행 확인) |
| ⑤ 데이터 태깅 | 분류 표시 | 거버넌스 스키마에 항목이 없다(실행 확인) |
④·⑤는 SROS 2 경로에 나타나지 않는다(실행 확인).
sros2가 배포하는 거버넌스 스키마(governance.xsd)에 로깅·태깅 항목이 없고, 생성되는 파일에도 없다. 표준에는 정의되어 있으나 ROS 2에서 쓰는 경로로는 닿지 않는다 — 실무에서 쓰이는 것은 ①②③이다.
견해: "인증 → 접근 제어 → 암호"의 순서로 이해하면 구조가 정리된다. 먼저 상대가 누구인지 확인하고(①), 그 신원이 무엇을 해도 되는지 정하고(②), 오가는 데이터를 보호한다(③). 각각 다른 파일과 설정에 대응한다.
13.3.3 인증
참여자가 그래프에 들어올 때 서로를 확인한다.
| 요소 | 설명 |
|---|---|
| 신원 CA | 신원 인증서를 서명한 루트 |
| 신원 인증서 | 참여자의 공개 신원 |
| 개인키 | 비밀 — 신원의 근거 |
| 핸드셰이크 | 상호 확인·키 합의 |
견해: 인증이 통과하지 못하면 그 참여자는 존재하지 않는 것과 같다. 그래프에 나타나지 않으므로
ros2 node list에도 안 보인다. "노드가 안 보인다"의 원인 목록에 인증 실패를 추가해야 한다(13.2.9).
함정: 인증서 유효기간과 시계(13.2.9의 반복). 로봇이 오래 꺼져 있다가 켜졌을 때 시계가 틀리면(RTC 배터리 방전 등) 인증이 실패한다. 시계 동기가 되기 전에는 통신이 안 될 수 있다는 점을 부팅 순서 설계(1.12)에서 고려해야 한다.
견해: CA를 어떻게 구성할 것인가가 규모의 문제가 된다. 로봇 한 대면 단순하지만, 수십~수백 대의 플릿에서는 발급·갱신·폐기를 자동화한 인증 기관 운영이 필요해진다. 이것은 IT 보안 인프라의 영역이며, 로봇 팀이 혼자 설계할 일이 아니다.
13.3.4 접근 제어 — 거버넌스와 권한
두 종류의 서명된 XML 파일이 있다.
| 파일 | 범위 | 내용 |
|---|---|---|
| 거버넌스(governance) | 도메인 전체 | 어떤 토픽을 어떻게 보호할지 |
| 권한(permissions) | 참여자별 | 무엇을 발행·구독할 수 있는지 |
<!-- 실제 sros2 가 생성하는 거버넌스와 동일한 형태다 (실행 확인 — 13.3.11) -->
<domain_access_rules>
<domain_rule>
<domains><id>0</id></domains>
<allow_unauthenticated_participants>false</allow_unauthenticated_participants>
<enable_join_access_control>true</enable_join_access_control>
<discovery_protection_kind>ENCRYPT</discovery_protection_kind>
<liveliness_protection_kind>ENCRYPT</liveliness_protection_kind>
<rtps_protection_kind>SIGN</rtps_protection_kind>
<topic_access_rules>
<topic_rule>
<topic_expression>*</topic_expression>
<enable_discovery_protection>true</enable_discovery_protection>
<enable_read_access_control>true</enable_read_access_control>
<enable_write_access_control>true</enable_write_access_control>
<metadata_protection_kind>ENCRYPT</metadata_protection_kind>
<data_protection_kind>ENCRYPT</data_protection_kind>
</topic_rule>
</topic_access_rules>
</domain_rule>
</domain_access_rules>
| 설정 | 의미 |
|---|---|
allow_unauthenticated_participants | true면 인증 없는 참여자 허용 — 위험 |
enable_join_access_control | 도메인 참여 자체를 통제 |
discovery_protection_kind | 디스커버리 보호(13.3.6) |
rtps_protection_kind | RTPS 메시지 수준 |
metadata_protection_kind | 메타데이터 |
data_protection_kind | 데이터 페이로드 |
함정:
allow_unauthenticated_participants를true로 두면 보안이 사실상 무력화된다. 개발 편의로 켜 두고 잊는 경우가 있으므로, 배포 점검에서 확인해야 한다(13.4).
견해: 거버넌스는 "무엇을 보호할지", 권한은 "누가 무엇을 할지"를 정한다. 이 둘을 혼동하면 설정이 충돌한다. 거버넌스는 도메인당 하나, 권한은 참여자마다 하나라는 대응을 기억하면 정리된다.
견해: 토픽별로 보호 수준을 달리할 수 있다는 점이 실무에 중요하다. 명령 토픽은 강하게, 대용량 센서 토픽은 성능을 고려해 다르게 설정할 수 있다(13.5).
topic_expression으로 규칙을 나누는 것이 그 수단이다.
13.3.5 보호 수준
기본은 세 가지이고, 항목에 따라 두 가지가 더 있다(실행 확인 — 전체 목록과 항목별 적용 범위는 13.3.11.2).
| 수준 | 제공 | 비용 |
|---|---|---|
| NONE | 없음 | 없음 |
| SIGN | 무결성·인증(변조 탐지) | 중간 |
| ENCRYPT | 기밀성 + 무결성 | 높음 |
SIGN_WITH_ORIGIN_AUTHENTICATION | + 보낸 참여자까지 검증 | 높음 |
ENCRYPT_WITH_ORIGIN_AUTHENTICATION | 위 둘을 합친 것 | 가장 높음 |
뒤의 둘은 data_protection_kind에는 쓸 수 없다(스키마가 그 항목만 세 가지로 제한한다 — 13.3.11.2). 페이로드는 양이 가장 많아 매 메시지에 참여자별 인증을 추가하는 비용이 감당되지 않기 때문이다.
| 대상 | 보호하지 않으면 |
|---|---|
| 데이터 | 내용 노출 |
| 메타데이터 | 타이밍·크기·시퀀스 노출 |
| 디스커버리 | 그래프 구조 노출(13.1.5) |
| RTPS | 하위 계층 조작 |
견해: "어떤 위협을 막으려는가"에서 수준을 정하라. 데이터 노출이 문제면
ENCRYPT, 변조가 문제면SIGN으로 충분할 수 있다. 명령 토픽은 변조·사칭이 핵심 위협이므로 최소한SIGN, 카메라 데이터는 기밀성이 문제이므로ENCRYPT가 맞다.
견해: 모든 것을
ENCRYPT로 두는 것이 안전하지만 비용이 크다(13.5). 특히 대용량 고빈도 토픽(포인트클라우드·이미지)에서 비용이 두드러진다. 위협 모델(13.1)에 근거해 차등하는 것이 합리적이며, 근거 없이 낮추는 것은 위험하다.
정직: 어떤 암호 알고리즘이 쓰이는지·설정 가능한지는 구현 의존이다
(확인 필요). 알고리즘 선택과 키 길이에 관한 판단은 보안 전문가의 영역이며, 이 책은 조언하지 않는다.
13.3.6 디스커버리 보호
놓치기 쉬운 부분이다.
| 노출되는 것 | 의미 |
|---|---|
| 참여자·노드 목록 | 시스템 구성 |
| 토픽 이름·타입 | 기능 추정 |
| QoS | 구현 세부 |
| 엔드포인트 | 공격 대상 식별 |
견해: 데이터를 암호화해도 디스커버리가 열려 있으면 시스템 구조가 드러난다. 13.1.5에서 "디스커버리 자체가 정보를 준다"고 한 것이 이것이다.
discovery_protection_kind를 확인하라.
함정: 디스커버리 보호는 상호운용성에 영향을 준다. 보호된 도메인에는 비보안 참여자가 접근할 수 없으므로, 개발 도구·모니터링 시스템도 인증 자료가 필요해진다. 운영 편의와의 절충을 미리 설계해야 한다(13.2.7의 도구용 enclave).
13.3.7 구현별 확인 사항
표준이 있어도 구현이 다르다.
| 확인 항목 | 왜 중요 |
|---|---|
| DDS-Security 지원 여부 | 미지원 구현도 있음(확인 필요) |
| 지원 플러그인 범위 | ④⑤는 흔히 제한 |
| 설정 파일 위치·형식 | 구현별 차이 |
| 성능 특성 | 암호화 비용(13.5) |
| 폐기(CRL) 지원 | 침해 대응(13.2.8) |
| 공유 메모리 전송과의 상호작용 | 제로 카피 영향(확인 필요) |
| 로깅·감사 | 사후 분석 |
정직: 3.5·3.6에서 RMW를 비교했듯, 보안 기능도 구현 선택의 축이 된다. 보안이 요구사항이라면 RMW 선택 시점에 지원 범위를 확인해야 하며, 나중에 바꾸는 것은 비용이 크다(3.6.7).
함정: 제로 카피·공유 메모리 전송과 암호화가 함께 동작하는지 확인하라
(확인 필요). 성능을 위해 도입한 최적화가 보안 설정에서 무효화되거나, 반대로 보안이 적용되지 않는 경로가 생길 수 있다. 12.3.5의 최적화와 이 장의 보호가 충돌하지 않는지는 반드시 확인할 사항이다.
견해: "보안을 켜고 성능을 다시 측정하라"(11.7). 12.4의 지연 예산은 보안 없이 측정한 것이라면 무효다. 보안 활성 상태의 측정값이 실제 운영 값이다.
13.3.8 진단
| 증상 | 확인 |
|---|---|
| 참여자가 안 보임 | 인증 실패·CA 불일치 |
| 인증은 되는데 토픽 없음 | 권한서 |
| 전체가 갑자기 실패 | 인증서 만료·시계 |
| 일부 토픽만 | 거버넌스 규칙·topic_expression |
| 성능 저하 | 보호 수준(13.5) |
| 비보안 노드가 연결됨 | allow_unauthenticated_participants |
# DDS 구현별 보안 로그 활성화 (확인 필요: 방법)
# 구현 문서를 따라 상세 로깅을 켜고 핸드셰이크 실패 원인 확인
견해: 보안 문제 진단은 DDS 구현의 로그에 의존한다. ROS 2 층에서는 "노드가 안 보인다"로만 보이므로, 구현별 상세 로깅을 켜는 방법을 미리 알아 두라. 이것을 모르면 진단이 추측이 된다.
견해: 문제를 좁히는 순서는 아래에서 위다(11.1.2). ① 두 참여자가 서로를 인증하는가 → ② 권한이 해당 토픽을 허용하는가 → ③ QoS가 맞는가. 보안을 끄고 되면 ①②, 꺼도 안 되면 ③.
13.3.11 거버넌스 파일의 실물과 스키마 — 실측
13.3.4가 보인 거버넌스 예시가 실제와 얼마나 같은지, 그리고 각 항목에 넣을 수 있는 값이 무엇인지를 확인했다. ros2 security create_keystore가 만든 파일과, sros2가 배포하는 XSD 스키마를 직접 열었다(실행 확인 — Jazzy · sros2 0.13.6 · ros:jazzy-ros-base 컨테이너). 파일 내용은 sros2 버전에 매인다(확인 필요).
13.3.11.1 기본 거버넌스는 이렇게 나온다
create_keystore 직후 <keystore>/enclaves/governance.xml의 전문이다(실행 확인 — 서명본은 governance.p7s):
<dds xsi:noNamespaceSchemaLocation="http://www.omg.org/spec/DDS-SECURITY/20170901/omg_shared_ca_governance.xsd">
<domain_access_rules>
<domain_rule>
<domains><id>0</id></domains>
<allow_unauthenticated_participants>false</allow_unauthenticated_participants>
<enable_join_access_control>true</enable_join_access_control>
<discovery_protection_kind>ENCRYPT</discovery_protection_kind>
<liveliness_protection_kind>ENCRYPT</liveliness_protection_kind>
<rtps_protection_kind>SIGN</rtps_protection_kind>
<topic_access_rules>
<topic_rule>
<topic_expression>*</topic_expression>
<enable_discovery_protection>true</enable_discovery_protection>
<enable_liveliness_protection>true</enable_liveliness_protection>
<enable_read_access_control>true</enable_read_access_control>
<enable_write_access_control>true</enable_write_access_control>
<metadata_protection_kind>ENCRYPT</metadata_protection_kind>
<data_protection_kind>ENCRYPT</data_protection_kind>
</topic_rule>
</topic_access_rules>
</domain_rule>
</domain_access_rules>
</dds>
기본값이 꽤 엄격하다. 인증 안 된 참가자를 거부하고(allow_unauthenticated_participants: false), 모든 토픽(*)에 읽기·쓰기 접근 제어를 걸며, 데이터와 메타데이터를 암호화한다.
정확히 한 곳만 SIGN이다 — rtps_protection_kind. 나머지는 전부 ENCRYPT인데 RTPS 계층만 서명이다.
견해: 이 비대칭이 우연이 아니다. RTPS는 패킷을 실어 나르는 바깥 계층이라, 완전히 암호화하면 중간 장비가 헤더를 읽지 못해 라우팅·진단이 막힌다. 서명은 변조를 막으면서 헤더는 열어 두는 절충이다. 즉 "안쪽(데이터·메타데이터)은 감추고, 바깥(전송 계층)은 위조만 막는다"로 읽으면 된다.
wireshark로 RTPS 패킷을 볼 수 있는 것도 이 설정 덕이다(3.2.8).
함정: 여기도 도메인이
0으로 고정된다. 13.2.12.2에서 권한 파일에 대해 본 것과 같은 문제다.ROS_DOMAIN_ID를 바꿔 쓰면 거버넌스와 권한 양쪽을 고쳐야 한다.
13.3.11.2 보호 수준은 다섯 단계다 — 한 항목만 세 단계
sros2가 배포하는 governance.xsd가 값을 명시해 두었다(실행 확인). 두 가지 타입이 있다.
| 타입 | 가능한 값 |
|---|---|
ProtectionKind(5종) | NONE · SIGN · ENCRYPT · SIGN_WITH_ORIGIN_AUTHENTICATION · ENCRYPT_WITH_ORIGIN_AUTHENTICATION |
BasicProtectionKind(3종) | NONE · SIGN · ENCRYPT |
어느 항목이 어느 타입인지가 중요하다:
| 항목 | 타입 | 즉 |
|---|---|---|
discovery_protection_kind | ProtectionKind | 5단계 |
liveliness_protection_kind | ProtectionKind | 5단계 |
rtps_protection_kind | ProtectionKind | 5단계 |
metadata_protection_kind | ProtectionKind | 5단계 |
data_protection_kind | BasicProtectionKind | 3단계 — origin authentication 불가 |
_WITH_ORIGIN_AUTHENTICATION은 "보낸 참여자가 맞는지까지 검증"한다. 여러 참여자가 같은 키를 공유하는 상황에서 그중 누가 보냈는지를 구분하려는 것인데, 그만큼 서명 연산이 늘어난다.
데이터 페이로드에만 그 옵션이 없다는 점이 설계 의도를 드러낸다. 페이로드는 양이 가장 많은 부분이라, 매 메시지에 참여자별 인증까지 추가하면 비용이 감당되지 않는다. 보내는 쪽을 가려야 한다면 메타데이터 계층에서 하라는 뜻이다.
함정:
NONE이 값 목록에 있다는 것을 기억하라. 성능 문제로data_protection_kind를NONE으로 낮추는 선택이 가능한데, 그러면 접근 제어는 유효하지만 페이로드는 평문이 된다. 네트워크를 신뢰할 수 있는 구간(유선 내부망)에서 의도적으로 쓸 수 있는 절충이지만, 무선 구간이 하나라도 끼면 그 순간 무의미해진다(3.9.3).
13.3.11.3 로깅·데이터 태깅 플러그인은 이 경로에 없다
13.3.2가 다섯 플러그인 중 ④로깅·⑤데이터 태깅을 (확인 필요)로 남겨 두었다. governance.xsd에 해당 항목이 전혀 없고, create_keystore가 만드는 어떤 파일에도 나타나지 않는다(실행 확인).
즉 표준에는 정의되어 있으나 SROS 2가 생성·서명하는 설정 경로로는 닿지 않는다. 보안 이벤트 로그가 필요하면 DDS 벤더가 따로 제공하는 설정(Fast DDS의 XML 프로파일 등, 3.7)을 찾아야 하며, ROS 2 표준 도구로는 켤 수 없다.
13.3.9 함정 카탈로그
| # | 함정 | 증상 | 대처 |
|---|---|---|---|
| 1 | allow_unauthenticated_participants 방치 | 보안 무력화 | 배포 점검 |
| 2 | 디스커버리 미보호 | 구조 노출 | discovery_protection_kind |
| 3 | 거버넌스·권한 혼동 | 설정 꼬임 | 역할 구분 |
| 4 | 전부 ENCRYPT | 성능 비용 | 위협 근거 차등 |
| 5 | 근거 없이 보호 완화 | 위험 | 위협 모델 기반 |
| 6 | 시계 오차 | 인증 실패 | 동기화·부팅 순서 |
| 7 | 도구용 자료 미발급 | 모니터링 불가 | 도구 enclave |
| 8 | RMW 보안 지원 미확인 | 도입 실패 | 선택 시점 확인 |
| 9 | 제로 카피와 충돌 미확인 | 최적화 무효·보안 공백 | 확인 |
| 10 | 보안 전 성능값 사용 | 예산 무효 | 재측정 |
| 11 | 구현 로그 모름 | 진단 불가 | 방법 확보 |
| 12 | 폐기 수단 미확인 | 침해 대응 제한 | 사전 확인 |
| 13 | 성능 때문에 data_protection_kind: NONE | 접근 제어는 살아도 페이로드 평문 | 무선 구간이 있으면 금지(13.3.11.2) |
13.3.10 체크포인트
- DDS-Security의 다섯 플러그인과, 실무에서 주로 쓰이는 셋은?
- "인증 → 접근 제어 → 암호"의 순서로 구조를 설명할 수 있는가.
- 인증 실패 시 그래프에서 어떻게 보이는가. 진단 목록에 무엇을 추가해야 하는가.
- 인증서 유효기간과 시계의 관계, 그리고 부팅 순서 설계에의 함의는?
- 거버넌스와 권한 파일의 범위·내용 차이는?
allow_unauthenticated_participants가 위험한 이유는?- 보호 수준의 값은 몇 가지이며,
data_protection_kind만 선택지가 적은 이유는? - 보호 대상 다섯 가지와, 각각을 보호하지 않으면 무엇이 노출되는가.
- 모든 것을 ENCRYPT로 하는 것의 문제와, 차등의 근거는?
- 디스커버리 보호가 왜 놓치기 쉬우면서 중요한가. 그 대가는?
- 구현별 확인 사항 일곱 가지와, RMW 선택 시점에 확인해야 하는 이유는?
- 제로 카피와 암호화의 관계에서 확인해야 할 것은?
- 보안 활성 후 성능을 재측정해야 하는 이유는?
- 보안 문제 진단의 순서와, 보안을 끄고 비교하는 것의 의미는?
- 보호 수준의 값은 몇 가지이며
data_protection_kind만 다른 이유는? 기본 거버넌스에서rtps_protection_kind만SIGN인 까닭은(13.3.11).
다음 장 13.4은 미들웨어 밖 — 운영 보안이다. 네트워크 격리, 시스템 강화, 업데이트, 비밀 관리.