# SROS2 관련 문제 해결 및 디버깅

#### 키 스토어(keystore) 디버깅

ROS2에서 보안을 적용하기 위해서는 먼저 키 스토어(keystore)를 올바르게 준비해야 한다. 키 스토어 내부에 들어가는 인증서나 권한(permissions) 파일이 잘못 구성되어 있으면 통신이 정상적으로 이루어지지 않는다. 다음과 같은 단계로 키 스토어 디버깅을 진행할 수 있다.

**키 스토어 디렉터리 구조 확인**: SROS2에서 사용하는 키 스토어는 일반적으로 다음과 같은 디렉터리 구조를 가진다.

```
keystore/
├── enclaves/
│   └── <enclave_name>/
│       ├── cert.pem
│       ├── key.pem
│       ├── permissions.xml
│       └── governance.xml
├── ...
```

* `enclaves` 폴더 안에 해당 노드가 사용할 인증서와 권한 설정 파일이 들어 있다.
* `cert.pem`과 `key.pem`은 각각 인증서와 개인 키이다.
* `governance.xml`과 `permissions.xml`이 잘못 배치되어 있으면 통신에 문제가 생길 수 있다.

**인증서와 키 파일 무결성 검사**:

* `cert.pem`과 `key.pem`은 짝이 맞아야 하며, 손상되지 않았는지 확인해야 한다.
* OpenSSL을 활용해 인증서 내용을 확인할 수 있다.

```bash
openssl x509 -in cert.pem -noout -text
```

* 인증서 내 Common Name(CN)이나 Subject Alternative Name(SAN)에 예상하는 노드 이름 혹은 도메인 관련 정보가 있는지 확인한다.

**governance.xml/permissions.xml 문법 확인**:

* XML 문법 오류가 있을 경우 노드 실행 시 Silent Failure(명시적 에러 메시지 없이 동작하지 않음)가 발생할 수 있다.
* XML 파서 혹은 IDE를 이용해 문법을 검증해본다.
* `<enclave>` 태그나 `<allow_rule>`, `<deny_rule>` 등의 설정이 올바른지 점검한다.

**키 스토어 권한(파일 퍼미션) 확인**:

* 키 스토어 폴더와 내부 파일에 대해 일반적으로 644나 600 정도의 퍼미션이 적절하다.
* 실제 ROS2 런타임을 구동하는 사용자 계정이 키 스토어에 접근 가능한지 확인한다.

```bash
ls -l keystore/
```

* 필요하다면 `chmod`, `chown` 명령으로 권한을 재설정한다.

**리눅스 환경변수 설정 점검**:

* SROS2를 사용하기 위해선 `$ROS_SECURITY_ROOT_DIRECTORY`나 `$ROS_SECURITY_NODE_DIRECTORY` 같은 환경변수를 올바르게 설정해야 한다.
* 예를 들어, 노드별 키 스토어 경로가 `$ROS_SECURITY_NODE_DIRECTORY`에 제대로 설정되어 있지 않다면 노드 실행 시 “Permission denied” 혹은 “Enclave not found” 등의 에러가 발생할 수 있다.

```bash
export ROS_SECURITY_NODE_DIRECTORY=/path/to/keystore/enclaves/my_node
```

#### SROS2 명령줄 도구 활용

ROS2에서는 보안 관련 아티팩트(인증서, 권한 설정 등)를 생성하고 확인하기 위한 명령줄 도구를 제공한다. 대표적으로 `ros2 security`가 있다.

**아티팩트 생성 문제 해결**:

* `$ ros2 security generate_artifacts -e <enclave_name> <keystore_path>` 명령으로 아티팩트를 생성할 때 에러가 발생한다면, Python 버전 혹은 OpenSSL 버전 등을 먼저 확인해본다.
* 더 자세한 디버깅 로그가 필요하다면 ROS2의 로깅 레벨을 DEBUG로 설정한다.

```bash
export RCL_LOG_LEVEL=DEBUG
ros2 security generate_artifacts -e my_enclave keystore/
```

**인증서 만료 혹은 재발급 문제**:

* 인증서가 만료되었거나 재발급 과정에서 오류가 생겼을 경우, 노드가 통신에 실패할 수 있다.
* 만료 여부는 인증서 안의 `Not After` 필드를 확인한다.

```bash
openssl x509 -in keystore/enclaves/my_enclave/cert.pem -noout -enddate
```

* 필요하다면 새로운 키 스토어를 생성하고, 해당 노드의 인증서를 재발급해준다.

#### 노드 간 통신 실패 시 확인 사항

보안이 활성화된 상황에서 노드 간에 통신이 되지 않는다면, 아래 사항을 순차적으로 확인해야 한다.

**DDS 보안 플러그인 동작 여부**:

* ROS2 보안 계층은 DDS 계층의 보안 플러그인을 활용한다. 만약 사용 중인 DDS 벤더의 보안 확장(예: RTI Connext, Fast DDS Security 등)이 제대로 설치되지 않았다면 통신이 실패한다.
* `$RCUTILS_LOG_LEVEL=DEBUG` 등으로 로깅 레벨을 높여 로그에서 DDS 보안 플러그인 오류를 확인한다.

**동일한 enclave 명칭 사용**:

* 두 노드가 서로 통신할 때, 서로 다른 키 스토어/Enclave를 사용하는 경우가 많다. 그러나 특정 보안 정책 하에서 같은 enclave를 사용해야 할 수도 있으므로, 해당 설정이 일관성 있는지 확인한다.
* `enclave` 이름이 잘못 지정되면 `permissions.xml` 매칭에 실패한다.

**QoS 설정 충돌**:

* SROS2 자체 이슈가 아니라 QoS 설정 충돌로 인해 통신이 되지 않는 경우도 있다.
* 상호 간 QoS가 호환되지 않으면 메시지 교환이 이루어지지 않는다. SROS2 보안 디버깅과 QoS 설정 문제가 혼재된 경우, 먼저 QoS를 기본값(예: `Reliable`, `Volatile` 등)으로 맞추고 테스트해본다.

#### 노드 실행 시 에러 로그 분석

ROS2에서 노드를 실행했을 때 보안 설정 문제로 오류가 발생하면, 다음과 같은 로그나 경고 메시지를 볼 수 있다.

* “Could not find matching key for enclave”
* “Access control policy not found”
* “DDS\_SECURITY: Failed to load identity CA”

위와 같은 오류가 떴을 경우 다음을 점검한다.

1. **Identity CA(cert.pem) 경로**
   * `$ROS_SECURITY_ROOT_DIRECTORY/identity_ca/` 내에 `cert.pem`이 존재해야 한다.
   * 혹은 `$ROS_SECURITY_NODE_DIRECTORY` 경로가 잘못 설정되어 인증서를 찾지 못하는 상황이 발생했는지 확인한다.
2. **퍼미션(permissions.xml) 매칭 여부**
   * 노드 이름이 `permissions.xml` 내 `<subject_name>`과 정확히 일치하는지 확인한다.
   * 와일드카드(`*`) 사용 시 범위가 의도한 대로 설정되었는지 검사한다.
3. **governance.xml 문제**
   * governance 설정에 따라 주요 정책(예: secure ROS topic 이름, discovery, liveliness 등)이 달라진다.
   * 만약 discovery가 제한되어 있으면 노드가 서로를 찾지 못할 수 있다.

#### 구성 불일치(Inconsistent) 문제

서로 다른 키 스토어 혹은 서로 다른 DDS 보안 구현체를 혼합해서 사용할 경우, 종종 “Inconsistent security configuration”과 같은 오류나 경고가 발생한다.

* OpenSSL 버전 차이나 DDS 보안 플러그인 버전 차이로 인해 인증서 파싱 과정에서 문제가 생기는 경우.
* 하나의 시스템 안에 여러 버전의 OpenSSL 라이브러리가 깔려 있어, 잘못된 버전을 참조할 수 있음.
* 서로 다른 DDS 벤더(예: RTI Connext, Fast DDS, Cyclone DDS 등)를 사용하는 노드가 동일한 enclave를 공유하려 할 때.

이러한 문제를 해결하기 위해서는 다음을 확인한다.

1. **DDS 버전 확인**
   * `$ apt list --installed | grep <DDS-implementation>` 등을 통해 설치된 버전을 확인한다.
   * 동일 ROS2 Humble 버전 내에서는 일반적으로 일치하는 DDS 버전을 사용하는 것이 바람직하다.
2. **OpenSSL 버전 호환성**
   * ROS2는 시스템에 설치된 OpenSSL을 사용하기 때문에, Ubuntu LTS 버전에 따라 OpenSSL 버전이 다르다.
   * 특정 OpenSSL 버전이 ROS2 보안 기능과 충돌을 일으키지 않는지, ROS2 공식 문서를 참고한다.

#### 인증서 체인(Certificate Chain) 점검

ROS2 보안은 인증서 체인을 통해 노드의 신뢰를 검증한다. 즉, Root CA → Intermediate CA → Node 인증서 순으로 이어지는 트러스트 체인을 형성해야 한다. 보통 SROS2 환경에서 Root CA와 Node 인증서만 사용하는 경우가 많지만, 중간 CA를 사용하는 시나리오에서도 아래 사항을 점검해야 한다.

**루트 인증서(Root CA) 신뢰성**:

* 모든 노드는 같은 루트 인증서를 통해 신뢰 체인을 형성해야 한다.
* Root CA 인증서가 만료되거나 노출된 경우에는 재발급 과정을 반드시 거쳐야 한다.

**중간 CA(Intermediate CA) 포함 여부**:

* `$ROS_SECURITY_ROOT_DIRECTORY/identity_ca/` 내부에 중간 CA 인증서를 배치했는지 확인한다.
* 중간 CA 인증서가 실제 체인에 포함되는지, OpenSSL 명령으로 확인할 수 있다.

```bash
openssl verify -CAfile root_ca.pem -untrusted intermediate_ca.pem node_cert.pem
```

* 인증서 경로 설정이 올바르지 않다면 체인 검증에 실패한다.

**시스템 시간 동기화**:

* 시스템 시계가 실제 시간과 크게 동떨어져 있으면, 인증서가 아직 유효 기간이 되지 않았거나 만료된 것처럼 인식될 수 있다.
* NTP 설정이나 Chrony와 같은 시간 동기화 데몬이 정상 동작하는지 확인한다.

#### 노드 이름 규칙 위반

ROS2에서 노드 이름에는 일부 예약된 문자나 포맷이 존재하며, 이는 보안 설정 시에도 중요하다.

**FQN(Fully Qualified Name) 구조**:

* ROS2 노드는 보통 `/namespace/node_name` 형태의 FQN(fully qualified name)을 갖는다.
* `permissions.xml`에서 `<subject_name>`에 노드 FQN을 정확히 기입해야 매칭된다.
* `namespace`를 바꾸면 FQN도 바뀌어 permissions가 달라지므로 주의해야 한다.

**스페이스나 특수문자 처리**:

* 노드 이름 혹은 토픽 이름에 스페이스나 허용되지 않는 문자가 포함되면, SROS2는 매칭에 실패한다.
* XML 내에 특수문자를 사용하는 경우, 반드시 엔티티(entity) 처리를 해주어야 한다.
* 예: `&` 문자는 `&`로 기입해야 한다.

#### 로컬 vs 원격 디버깅 전략

SROS2를 적용한 환경에서 로컬 노드 간 통신은 정상인데, 원격(다른 호스트) 노드 간 통신만 실패하는 경우가 있다. 이때 다음 사항을 확인한다.

**파이어월(firewall) 설정**:

* DDS 보안이 활성화되어도 DDS가 사용하는 포트들은 열려 있어야 한다.
* Ubuntu iptables나 firewalld, 혹은 클라우드 환경의 Security Group 설정 등을 점검한다.

**보안 인증서 동기화**:

* 로컬에서 생성한 키 스토어를 원격 호스트로 복사해 넣은 후, 경로 설정을 제대로 했는지 확인한다.
* 중간에서 cert.pem, key.pem 등이 손상되거나 누락되지는 않았는지 점검한다.

**ROS\_DOMAIN\_ID 일치 여부**:

* 여러 호스트 간 통신 시, `ROS_DOMAIN_ID`가 동일해야 동일한 DDS 도메인 내에서 노드를 발견하고 통신할 수 있다.
* SROS2 보안이 잘 되어 있어도 도메인 아이디가 불일치하면 서로를 찾지 못한다.

#### 디버깅 툴/명령어 활용

SROS2 디버깅은 ROS2 로깅 레벨 및 DDS 자체의 로깅 기능을 적극 활용해야 한다.

1. **ROS2 로깅 레벨**
   * `$export RCL_LOG_LEVEL=DEBUG` 또는 `$ export RCUTILS_CONSOLE_OUTPUT_FORMAT="[{severity}]: {message}"` 등을 통해 로그를 상세히 확인한다.
   * 보통 “DDS\_SECURITY” 키워드를 포함한 로그에서 문제 원인이 나타난다.
2. **DDS 로그(예: Fast DDS, Cyclone DDS)**
   * Fast DDS를 사용한다면, `$ export FASTRTPS_DEFAULT_PROFILES_FILE=...` 설정을 통해 자체 로깅 레벨을 높인다.
   * Cyclone DDS의 경우, `CYCLONEDDS_URI`를 이용해 `<Tracing>` 옵션을 설정한다.
   * DDS 레벨에서 어떤 security handshake가 실패하는지 추적할 수 있다.
3. **Wireshark 활용**
   * DDS RTPS 패킷을 캡처해 보안 handshake 패킷(secure handshake) 교환이 일어나는지, 어떤 부분에서 중단되는지 파악할 수 있다.
   * 이 방법은 로우레벨 네트워크 패킷 디버깅이 필요할 때만 사용한다.

#### 예제: SROS2 TLS handshake 실패 시나리오

TLS handshake는 노드가 서로 인증서를 교환하며 신뢰 여부를 확인하는 절차다. 이 단계에서 자주 발생하는 문제 예시는 다음과 같다.

**인증서 Mismatch**:

* 노드 A에서 사용하는 cert.pem과 key.pem이 짝이 맞지 않아 TLS handshake가 실패한다.
* 각 노드의 `cert.pem`과 `key.pem`을 OpenSSL 명령으로 유효성 점검해본다.

```bash
openssl rsa -in key.pem -noout -modulus | openssl md5
openssl x509 -in cert.pem -noout -modulus | openssl md5
```

* 두 명령의 해시값이 같아야 한다.

**서버/클라이언트 역할 혼동**:

* DDS 보안 계층에서 노드는 서로 Peer-to-Peer(P2P) 형태로 인증서를 교환하지만, 내부적으로는 서버/클라이언트 로직이 동시에 동작한다.
* 특정 DDS 벤더마다 설정(특히 Access Control)이 다른 경우가 있어, 설정 파일이 호환되지 않으면 실패한다.

**CA 체인 확인 불가**:

* Node 인증서가 올바른 CA 체인에 속해 있지 않으면, “unknown ca” 혹은 “certificate verify failed” 오류가 난다.
* `$ ssl verify ...` 등을 통해 실제 인증서 체인을 점검해본다.

#### 에페머럴(임시) 키 스토어와 테스트

ROS2 애플리케이션을 개발하거나 테스트 환경에서 SROS2 설정을 간단히 검증하고 싶을 때, 지속성 있는(파일로 남는) 키 스토어 대신 에페머럴(임시) 키 스토어를 사용하는 방법이 있다. 에페머럴 키 스토어는 테스트 시나리오가 끝나면 삭제되어, 보안 위험을 줄이고 빠르게 CI/CD에 통합할 수 있다는 장점이 있다.

**임시 디렉터리 사용**:

* 테스트 스크립트 혹은 CI 파이프라인에서 `/tmp` 디렉터리를 활용하여 키 스토어를 생성한다.

```bash
mkdir -p /tmp/keystore
ros2 security generate_artifacts -e test_node /tmp/keystore
```

* 테스트가 종료된 후 `/tmp/keystore`를 삭제한다.

**권한 설정 최소화**:

* 에페머럴 키 스토어는 어디에도 백업되거나 복사되지 않도록 주의한다.
* 파일 퍼미션을 `700`(소유자만 접근 가능) 정도로 최소화해 보안 사고를 방지한다.

**CI/CD와 연동**:

* Jenkins, GitHub Actions 등에서 테스트 전용 키 스토어를 생성하고, 테스트가 끝나면 바로 제거한다.
* 덕분에 보안 파일이 코드 저장소에 커밋되지 않아 민감 정보 노출을 막는다.

#### 키 회전(Key Rotation) 문제

보안 정책상 일정 주기로 인증서와 키를 갱신(키 회전)해야 하는 경우가 있다. 키 회전 시 노드 간 통신이 중단되지 않도록 주의해야 한다.

**부분 교체 vs 전체 교체**:

* **부분 교체**: 특정 노드만 인증서를 재발급받아 키 스토어를 갱신한다. 다른 노드는 기존 키 스토어를 유지한다.
* **전체 교체**: 전체 시스템의 키 스토어를 한꺼번에 재생성한다. 대규모 시스템일수록 다운타임이 길어질 수 있어 신중해야 한다.

**중간 CA 활용**:

* 중간 CA를 두어 Node 인증서를 재발급할 때, Root CA는 건드리지 않고 중간 CA 레벨에서만 교체한다.
* 이를 통해 시스템 전체 신뢰 구조를 유지하면서 개별 노드의 인증서만 자주 교체할 수 있다.

**노드 재시작 vs 핫 스와핑**:

* 일부 DDS 구현체는 노드 재시작 없이 인증서 재적용이 어려울 수 있다.
* 재시작 없이 핫 스와핑을 지원하는지, 해당 DDS 보안 플러그인의 문서를 참고한다.

#### 노출된 노드(Compromised Node) 처리

만약 해커에 의해 특정 노드의 인증서와 개인 키가 유출되었을 가능성이 있다면, 다음 과정을 통해 영향을 최소화해야 한다.

**해당 노드 키 폐기**:

* 해당 노드 Enclave에 대하여 새로운 인증서와 키를 발급한다.
* 기존 인증서와 키는 폐기하고, 관련된 permissions.xml에서 노드의 권한을 일시적으로 제거한다.

**CRL(Certificate Revocation List) 확인**:

* DDS 레벨에서 CRL을 지원하는 경우, 유출된 인증서를 즉시 블랙리스트에 넣어 다른 노드가 신뢰하지 않도록 한다.
* CRL 기능이 미흡하다면, Root CA 교체나 중간 CA 교체 방법을 고려해야 한다.

**감염 범위 평가**:

* 노출 노드가 어떤 Topics, Services에 접근했는지 `governance.xml`, `permissions.xml` 분석을 통해 파악한다.
* 다른 노드가 추가로 침해되었을 가능성을 염두에 두고, 수시로 키 스토어 상태를 점검한다.

#### 멀티 엔클레이브 환경(Multi-enclave Environment) 디버깅

프로젝트 규모가 커질수록 노드마다 혹은 기능별로 다른 Enclave를 사용하는 경우가 많다. 이때 엔클레이브 간 인증 및 권한 설정이 복잡해질 수 있다.

**엔클레이브 계층 구조**:

* 예: `/robot/camera`와 `/robot/navigation` 등 독립된 Enclave를 구성하고, 필요한 Topic만 상호 구독하도록 governance, permissions를 작성한다.
* 엔클레이브 이름이 길거나 복잡하면 XML 설정 시 오타가 발생하기 쉽다.

**Cross-enclave Topic 허용 여부**:

* governance.xml에서 Topic discover, join, access에 대한 정책을 엔클레이브별로 정확히 설정했는지 확인한다.
* `/robot/camera`에서 `/robot/navigation`의 Topic에 데이터를 Publish할 수 있는지, 실제 권한이 열려 있는지 점검한다.

**브리지 노드(Bridge Node)**:

* 서로 다른 엔클레이브 간 데이터 중계를 위해 브리지 노드를 두기도 한다.
* 브리지 노드는 두 개 이상의 Enclave에 속하거나(실무적으로는 흔치 않음), 노드 내부 로직으로 각 Enclave를 전환하며 메시지를 재전송한다.
* 이때 브리지 노드가 필요 이상의 Topic 권한을 갖지 않도록 설정이 중요하다.

#### SROS2와 교차 컴파일(Cross-compiling)

임베디드 기기나 ARM 보드 등에서 ROS2 Humble을 동작시킬 때, 교차 컴파일을 진행한다면 보안 아티팩트 역시 교차 컴파일 환경에서 준비해야 하는 경우가 있다.

**Native vs Cross Toolchain**:

* 인증서 생성과 관련된 OpenSSL 등 툴체인은 PC(호스트)에서 동작할 가능성이 크다.
* 생성된 인증서와 키는 Target 장치(임베디드 보드)로 옮겨서 사용한다.

**확장성(Scalability) 문제**:

* 임베디드 장치가 많으면, 각각의 노드/엔클레이브에 대한 키 스토어를 대량으로 생성해야 한다.
* 자동화 스크립트를 통해 일괄 생성하는 방안을 마련한다.

**퍼포먼스 측정**:

* SROS2 보안 인증/암호화 과정이 임베디드 장치 CPU에서 부담이 되지 않는지 확인한다.
* CPU 성능이 낮은 보드일수록 인증서 검증 시간이 길어질 수 있으므로, 최적화된 DDS 보안 플러그인(예: HW 가속, AES-NI 등)을 고려한다.

#### mermaid 예시: DDS 보안 Handshake 개념도

아래 예시는 노드 간 DDS 보안 핸드셰이크 과정을 단순화하여 표현한 것이다. (실제 DDS 보안 프로토콜은 더 많은 스텝이 존재)

{% @mermaid/diagram content="sequenceDiagram
participant NodeA
participant NodeB
NodeA->>NodeB: Hello(Identity Request)
NodeB->>NodeA: Identity Response (Certificate, Signed Tokens)
NodeA->>NodeB: Validate & Send Shared Key
NodeB->>NodeA: Acknowledgement
Note over NodeA,NodeB: Secure channel established" %}

* `Hello(Identity Request)`: NodeA가 NodeB에게 인증서나 식별 정보를 요청한다.
* `Identity Response`: NodeB가 자신의 인증서와 일부 서명된 토큰 정보를 NodeA에 전송한다.
* `Validate & Send Shared Key`: NodeA는 받은 인증서를 검증한 뒤, 세션 키(공통 암호화 키)를 NodeB에 안전하게 전송한다.
* `Acknowledgement`: NodeB가 세션 키를 수신 및 검증하고 Secure Channel을 공식적으로 성립시킨다.

#### 추가 디버깅 팁

1. **Time Sync 재확인**
   * 인증서 유효 기간과 관련된 모든 오류의 상당수가 시스템 시계 불일치로 인해 발생한다.
   * 물리적으로 떨어진 장치에서는 NTP 서버 설정이 올바른지 체크한다.
2. **Node 프로세스 권한**
   * Docker 컨테이너나 chroot 환경에서 노드가 실행된다면, 컨테이너 내부 경로와 실제 호스트 경로가 달라 SROS2 설정이 꼬일 수 있다.
   * `--security-keystore` 옵션으로 직접 경로를 지정하는 것이 혼동을 줄여준다.
3. **policy 파일 반복 검사**
   * 보안 정책을 수시로 변경해야 하는 프로젝트라면, git diff 등을 활용해 작은 변경 사항도 추적 가능하게 만든다.
   * 예: `<allow_rule>` 하나가 추가되었는지, `<deny_rule>`가 삭제되었는지 등.
