strongSwan 구성에 연결을 나열하는 것은 정의가 로드되었다는 것만 증명한다. 피어에 접속했다거나 IKE SA가 존재한다거나 어떤 트래픽이 보호된다는 뜻은 아니다. 데몬은 정의와 살아 있는 연결을 별개의 객체로 다루며, 둘 사이의 거리는 의도된 설계 선택이다. 어떤 객체를 살펴보고 있는지 알면 모호한 장애가 구체적인 다음 명령으로 바뀐다.

로드는 연결이 아니다

로드된 연결은 피어 주소, 자격 증명, 제안, 트래픽 선택자 등 나중에 협상할 수 있는 것에 대한 진술이다. 그 진술 어디에도 데몬이 누군가에게 전화를 걸어 두어야 한다는 요구는 없다. 게이트웨이는 상대편을 기다릴 수도, 시작할 때 스스로 개시할 수도, 일치하는 트래픽이 깨워 주기를 기다릴 수도 있다. 세 가지 모두 유효하며, 시작 정책을 읽기 전까지는 구성 파일에서 똑같이 보인다.

운영자가 빠지는 함정은 정의 목록을 상태 목록으로 읽는 것이다. 프로파일이 있으니 터널이 올라와 있다고 가정하고, 다음 한 시간을 한 번도 만들어진 적 없는 연결의 경로를 디버깅하는 데 쓴다.

반대의 실수도 그만큼 흔하다. 프로파일이 없으면 구성이 한 번도 로드되지 않았는데도 네트워크 장애를 찾아 나선다. 객체에 이름을 붙이고, 그다음 그것을 관찰하는 명령을 실행한다.

세 객체, 세 관찰

strongSwan은 로드된 정의, IKE SA, CHILD SA를 유지한다. 첫째는 구성이고, 둘째는 인증된 제어 관계이며, 셋째는 선택된 트래픽에 대해 협상된 보호다. 이름도 따로 있어서 hq라는 프로파일이 hq-lan이라는 child를 가질 수 있다.

표는 각 계층을 그것을 보여 주는 명령과 연결한다. 로그를 읽기 전에 그 행을 읽는다.

LayerWhat it containsCommand
DefinitionPeer addresses, credentials, proposals, and traffic selectorsswanctl --list-conns
IKE SAOne authenticated control channel to the peerswanctl --list-sas
CHILD SAKeys and selectors for the traffic being protectedChild rows under the IKE SA

child를 요청하면 없을 때 먼저 부모 IKE SA를 만든다. IKE SA만 요청하는 것은 다른 호출이다. 올바로 인증되는 제어 채널도 요청한 child를 보장하지 않는다.

이 차이는 부분 장애에서 중요하다. IKE SA는 건강할 수 있지만 child는 선택자 불일치나 피어가 받아들이지 않는 제안 때문에 실패한다. 두 객체는 서로 다른 이유로 실패하므로 따로 관찰할 가치가 있다.

시작 동작을 의도적으로 고른다

swanctl.conf에서 child의 start_action은 로드 이후 동작을 결정한다. 기본값 none은 정의를 수동 시작이나 responder 용도로 남겨 둔다. start는 호출하고, trap은 일치하는 트래픽이 나타나는 즉시 협상하는 정책을 남긴다.

따라서 «로드는 결코 터널을 시작하지 않는다»와 «로드는 항상 하나를 시작한다» 모두 틀렸다. 동작은 프로파일의 일부이며 피어의 역할과 맞아야 한다. 둘 다 상대편을 기다리는 두 게이트웨이는 침묵을 만들 뿐 터널을 만들지 않는다.

trap에서는 트래픽이 선택자와 일치해야 하므로 무관한 ping은 아무것도 깨우지 않는다. start에서는 피어 주소가 사용 가능해야 하고 양쪽이 인증과 제안에 합의해야 한다. 어느 동작도 이러한 전제의 확인을 대신하지 않는다.

복구는 별도의 정책이다

시작은 keepalive가 아니다. 죽은 피어 감지, 피어의 명시적 종료, 키 갱신, 프로세스 재시작은 각자의 설정을 가진 서로 다른 수명 주기 사건이다. 최초 시작이 그것들을 모두 덮으리라 기대하는 대신 하나씩 의도적으로 구성한다.

부팅 시 올라와 한 시간 뒤에 죽는 터널은 복구의 문제다. 시작 정책은 제 일을 마쳤고 그 뒤로는 중요하지 않게 되었다. 최초 협상을 탓하기 전에 DPD와 키 갱신 설정을 본다.

로드된 정의를 교체하는 것은 별개의 작업이다. 기본이 아닌 시작 정책에는 문서화된 역동작이 있고, 다시 로드하는 것은 운영상의 변경이며 모든 연결이 제자리에서 갱신되었다는 가정이 아니다. 다시 로드는 재접속이 허용되는 단계에서 수행한다. 새 구성이 증명될 때까지 옛 구성을 유지한다.

라우팅을 디버깅하기 전에 무엇이 존재하는지 확인한다

세 관찰, 즉 로드된 정의, 활성 IKE SA, child 항목을 순서대로 수행한다. 답이 나올 때마다 다음 질문이 좁아진다. 한 단계를 건너뛰면 결국 한 번도 만들어진 적 없는 계층을 디버깅하게 된다.

로드된 것과 실제로 성립된 것부터 시작한다:

swanctl --list-conns
swanctl --list-sas

프로파일이 올바른데 child가 없다면 이름으로 시작하고 무슨 일이 일어나는지 본다. 보통 출력은 부모가 먼저 올라왔는지 알려 준다.

swanctl --initiate --child hq-lan

활성 CHILD SA는 결승선이 아니다. 전달 규칙, 경로, 애플리케이션 자체의 권한이 여전히 맞아야 한다. 수명 주기는 무엇을 협상했는지 답하지만, 누가 서비스를 쓸 수 있는지는 결정하지 못한다.

관련 글