SigStore Ruby: 순수 Ruby로 소프트웨어 보안 검증 클라이언트 구축하기

[EN] The Challenges of Building sigstore-ruby / Samuel Giddins @segiddins

작성자
RubyKaigi
발행일
2025년 05월 27일

핵심 요약

  • 1 sigstore-ruby는 RubyGems 및 Bundler에 통합되어 사용되는 순수 Ruby 기반의 Sigstore 검증 및 서명 클라이언트입니다.
  • 2 Ruby 표준 라이브러리의 제한된 암호화 프리미티브 지원과 JRuby, TruffleRuby 등 다양한 Ruby 구현체 지원으로 인해 수많은 하위 암호화 및 프로토콜 기능을 직접 구현해야 했습니다.
  • 3 Sigstore 프로토콜의 복잡성과 여러 암호화 시스템(X509, TUF, Merkel trees, Signotes)의 결합은 구현을 어렵게 만들었지만, 이는 사양의 정밀성과 이식성을 높이는 데 기여했습니다.

도입

본 발표는 Ruby Central의 보안 엔지니어인 Samuel Giddens가 RubyKaigi에서 진행한 'SigStore Ruby' 개발 경험에 대한 내용입니다. Sigstore Ruby는 소프트웨어 아티팩트의 출처를 암호학적으로 검증하고 서명하는 순수 Ruby 구현체로, RubyGems.org의 젬 페이지 하단에 젬의 출처(GitHub Actions에서 빌드 및 서명되었는지 여부)를 표시하는 데 사용됩니다. 본 발표에서는 Sigstore Ruby를 구축하는 과정에서 직면했던 기술적 난관과 그 해결 과정, 그리고 Ruby 생태계에 대한 시사점을 다룹니다.

Sigstore 클라이언트는 기본적으로 두 가지 핵심 기능을 수행합니다. 첫째, 아티팩트와 Sigstore 번들이 신뢰할 수 있는 루트에 대해 일치하는지 검증합니다. 둘째, 아티팩트를 신뢰할 수 있는 루트에 대해 암호학적으로 서명합니다. 이 두 기능은 겉보기와 달리 매우 복잡하며, Sigstore는 서명, 검증, 출처 확인을 위한 다양한 기술(X509 PKI, TUF, Merkel trees, Signotes)의 통합체입니다.

Sigstore Ruby 구현 목표 및 도전 과제

  • 순수 Ruby 구현: 서명 및 검증 흐름 모두 순수 Ruby로 구현하는 것이 목표였습니다. 이는 RubyGems 및 Bundler 내부에 100% 벤더링(vendoring)되어 Ruby 배포판에 포함될 수 있도록 하기 위함입니다.
  • 신규 암호화 코드 작성 회피: 기존 암호화 라이브러리를 최대한 활용하고 신규 암호화 코드 작성을 피하는 것이 중요한 목표였습니다.

‘순수 Ruby’의 정의는 ISO Ruby, mini Ruby, 표준 라이브러리만 사용 등 다양하지만, 실제로는 MRI, JRuby, TruffleRuby의 비EOL(End-of-Life) 버전에서 모두 작동하는 코드를 의미합니다. 그러나 업계 표준 라이브러리의 대부분이 C로 작성되어 있고, Ruby 표준 라이브러리의 프리미티브 또한 상당 부분 네이티브 코드로 구현되어 있어 순수 Ruby로 복잡한 암호화 기능을 구현하는 것은 매우 어려운 작업입니다.

암호화 프리미티브의 한계와 직접 구현

Sigstore 클라이언트 구현에는 Google의 Protocol Buffers (JSON 인코딩), RSA, ECC DSA, ED25519와 같은 다양한 암호화 서명 알고리즘, X.509 서명 인증서, RFC 3161 서명 인증서 타임스탬프, Merkel tree, 두 가지 JSON 정규화 형식 등 수많은 프리미티브가 필요합니다. 하지만 Ruby 표준 라이브러리(특히 OpenSSL Gem)는 이러한 요구사항을 모두 충족하지 못했습니다.

  • OpenSSL Gem의 한계: 특정 OpenSSL 버전에서 ED25519 미지원, 인증서 속성 쿼리 기능 부족, X.509 확장 OID 처리 문제, to_be_signed_prescertificate 바이트 추출 미구현, 서명된 인증서 타임스탬프 및 RFC 3161 검증 기능 부족 등이 있었습니다. 이 중 상당수는 Samuel Giddens가 직접 PR을 보내거나 순수 Ruby로 재구현해야 했습니다.
  • JRuby OpenSSL의 추가적인 한계: JRuby OpenSSL은 Bouncy Castle 기반으로 구현되었으며, 중간 CA를 통한 X.509 경로 검증 버그, ED25519 미지원, 공개 키 DER 내보내기 미지원 등 C Ruby Gem보다 더 많은 기능이 누락되어 있었습니다. 결국 JRuby에서 Sigstore Ruby를 작동시키기 위해 원시 Java.security API를 직접 사용하는 코드를 작성해야 했습니다.

이러한 제한된 환경으로 인해 Sigstore Ruby 자체적으로 X.509 래퍼, RFC 8785 JSON 정규화, ASN.1 바이트 조작을 통한 인증서 정보 추출, 서명된 인증서 타임스탬프 및 RFC 3161 지원, DESI(Dead Simple Security Envelopes) 지원, 그리고 TUF(The Update Framework) 클라이언트까지 직접 구현해야 했습니다. 이는 두 가지 기능 구현을 위해 예상보다 훨씬 많은 하위 시스템을 구축해야 했음을 의미합니다.

결론

Sigstore는 X509, TUF, Merkel trees, Signotes 등 여러 시스템의 복합체이며, 각각의 시스템은 복잡한 설정 지점을 가지고 있어 구현의 난이도를 높였습니다. 하지만 `sigstore-ruby`와 같은 새로운 클라이언트 구현은 기존 구현에서 발견된 버그의 영향을 완화하고, Sigstore 사양을 더욱 정밀하고 이식 가능하게 만드는 데 기여합니다. 2024년에는 여러 적합성 테스트 스위스, 개선된 클라이언트 문서, 그리고 다른 구현체 간의 수렴 덕분에 다음 클라이언트 개발은 더욱 수월해질 것입니다. Samuel Giddens는 이러한 경험을 통해 Ruby 커뮤니티가 이와 같은 소프트웨어 구축을 더 쉽게 만들 수 있도록 영감을 얻기를 바라며, `sigstore-ruby` 프로젝트에 대한 관심과 기여를 독려했습니다.

댓글 0

댓글 작성

0/1000
정중하고 건설적인 댓글을 작성해 주세요.

아직 댓글이 없습니다

첫 번째 댓글을 작성해보세요!