테스트 환경을 구축하면서 정리한 문제점들


오늘의 문제 1

내가 Rust로 서비스 코드를 작성한다고 해서, 테스트까지 Rust로 작성하고 싶은 것은 아니다.

그냥 Web Crypto API를 이용하는 클라이언트를 써서 End-to-end test를 구현하고 싶은데 그럴려고 보니까 Deno 혹은 Node를 써서 테스트 코드를 작성하고 싶어졌다.

그러고 보면 컴파일 언어의 특성 상 테스트마저도 컴파일한다 어쩐다 하는것도 뭔가 불필요해 보이고, 테스트니까 바이너리가 빠르게 돌아가는 것보다는 여러 API를 쉽고 편하게 쓸 수 있는 것이 좋은데 Rust는 라이브러리들도 사용성보다는 성능 최우선으로 작성된 경우가 많아서 편하게 쓰기가 쉽진 않다.

일단 Crypto API를 Mocking하는 것도 말이 안되고 해서 그냥 Rust에서 Integration test 코드를 하나 추가하고, 그 코드에서 Deno를 바로 실행하게 해서 실제 테스트가 돌아가도록 했다는 결말. 아 시원하다.

오늘의 문제 2

시스템 테스트하다가 전체공개가 아닌 외부 의존성을 필요로 하는 경우가 생겼다.

좀 어이없는 상황이긴 한데, 웹 클라이언트에서 Web Crypto API를 이용해서 생성한 signature를 검증하는데 Rust 구현을 하기가 싫어서 “마이크로서비스”해버린 API가 하나 있다. Deno로 구현한 서버가 딱 signature verification만 하도록 구현해 놓고 이걸 호출하도록 구현한 것이다.

(그러고보면 서버를 모조리 Javascript로 구현했으면 고민할 일도 없었겠다;;)

DevOps 경험이 일천한 상태에서 개발자 편의 위주로 시스템을 구성하려니 이부분도 쉽지가 않다. 대략 다음과 같은 선택지가 가능할 것 같은데:

  • Zero trust를 부르짖으며 모든 마이크로서비스를 public internet에 공개, 모든 클라이언트/서버에서 일관된 AAA 프로토콜을 정의 및 구현 -> ㅅㅂ 이게 어떻게 개인 프로젝트냐
  • 프로덕션 서버를 돌리는 환경을 docker-compose로 구성, private network를 사용해서 서비스끼리의 통신이 외부로 새어나가는 일이 없도록 차단, 그러니 로컬에서도 프로덕션과 동일하게 모든 서비스를 띄우십시오. -> 로컬 사양이 딸려서 마구 터진다!
  • docker-compose까지는 동일한데 loopback 포트는 열어준다. 로컬에서는 프로덕션 서버에 터널을 뚫어서 쓰시면 됩니다 -> 개발할 때마다 터널 뚫어서 하라는 말이냐 너무 번거롭다 엉엉

남의 문제 3

서버가 인증서 관리도 해야 하냐 reverse proxy에 맡겨도 되나

요즘 https 인증서들은 약해빠졌다. 옛날에는 1년+이상 긴 기간동안 유효한 인증서들을 써서 인증서 갱신이 마치 은행 웹사이트에서 공인인증서 갱신하는 것처럼 개발자가 직접 처리해야 하는 번거로운 작업이었는데, 요즘은 3개월만 지나도 큰일이 난것처럼 “더이상 유효하지 않습니다”에러를 뱉어내기 때문에 더이상 수작업으로 인증서를 관리할 수가 없게 되었고, let’s encrypt같은 인증서 발급 시스템과 연동을 해서 자동으로 일정기간마다 인증서를 갱신하는 것이 업계 표준으로 자리잡게 되었다.

그런 문제도 있고 다수의 연결을 효율적으로 관리하는 문제도 있고 load balancing 문제도 있고 해서 사실 대부분의 웹 서버는 http만 구현해 놓고 외부 연결은 Nginx 등의 reverse proxy를 거치는 게 일반적이긴 하다. 직접 인증서를 다루고 싶다고 해도 rotation은 번거로운 작업이고, 직접 구현할 때 고려할 사항이 적지 않다.

그럼에도 불구하고 그런 기능을 가볍게 지원할 수 있으면 지원해주는 것이 좋다고는 생각하지만, 한번에 한가지 기능만 빠르고 완벽하게 구현하는 것이 여러 기능을 복잡하게 지원하는 것 보단 낫다고 보기 때문에 reverse proxy를 강제하기로 한 결론에 문제는 없다고 생각한다.