Secret을 Git에 Track하여 관리할 수 있는 CLI 솔루션을 작성하고, 이를 오픈소스로 공개해봤습니다.
https://www.npmjs.com/package/@unknownpgr/git-key
Motivation
어느날 프로젝트를 진행하면서 secret 관리가 꽤 번거롭다는 것을 깨달았습니다.
이 프로젝트의 백엔드는 대략 api server
, database
, redis
세 가지의 온프레미스 서비스로 구성되며 그중 api server
는 DB 및 Redis와 함께 AWS S3에 의존성을 가집니다. 이들은 개인 서버 위의 쿠버네티스 환경 위에서 동작하고 있습니다. 따라서 이 서비스를 운영하기 위해서는 이 세 가지 서비스에 계정과 credential, 포트 등 각종 설정을 환경 변수나 config 파일을 비롯한 다양한 방법으로 제공해주어야 합니다. 특히 이 모든 서비스들과 연결되는 api server
는 10개가 넘는 환경 변수 설정이 필요합니다.
그런데 이 값들은 모두 외부에 노출되면 안 되는 secret들입니다. 그러므로 보안을 위하여 Docker image에 포함하거나 private repository를 사용한다고 하더라도 Git에 track할 수 없습니다. 즉, 이 모든 값을 설정을 통해 공급해주어야만 합니다. 그리고 GitHub action을 통해 빌드나 테스트를 수행할 경우 GitHub의 설정을 통해서 이 값들을 설정해주어야 하며, 여러 사람이 공동으로 프로젝트를 진행하는 경우 이러한 secret들을 공유해야 합니다.
특히 어떤 secret들은 개발 과정에서 그 값이 자주 바뀔 뿐 아니라 새로운 secret이 추가되거나 없어지고, 환경 변수를 사용하다가 json 파일을 사용하는 등, 그 형식 역시 자주 바뀌었습니다. 그러다 보니 secret 관리에 걸리는 시간도 적지 않았습니다.
Solutions
이런 불편함을 해결하고자 아래와 같은 조건을 만족시키는 솔루션들을 조사했습니다.
- Secret을 git을 통해 안전하게 track할 수 있어야 한다.
- 설치 및 사용이 대단히 간단해야 한다.
- 운영체제 및 Git에 종속성이 있으면 안 된다.
- 무료여야 한다.
- 프로젝트 외부에 의존성이 있으면 안 된다.
그러나 제가 찾아본 솔루션들은 위 조건을 만족시키지 못했습니다. Git-Secret이라는 솔루션이 제일 마음에 들었는데, Git-Secret은
- GPG를 사용하여 그 사용 방법이 복잡하고
- Git에 의존성이 있으며
- 운영체제 버전에 따라 다르게 동작할 수 있음을 알게 되었습니다.
이에 따라 제 요구사항을 만족시키는 솔루션을 개발하기로 했습니다.
Decisions
가장 먼저 솔루션의 형태를 결정했습니다.
- 바이너리도 나쁘지는 않지만 저는 주로 Node.js를 사용하므로 npm으로 쉽게 설치할 수 있는 Node.js의 패키지를 택했습니다.
- 본 솔루션은 프로그램의 실행과 무관하게 작동하므로 CLI 툴 형태로 구현했습니다.
- 단 추후 확장가능성을 고려하여 프로그램에서 import하여 사용할 수 있는 구조로 작성했습니다.
다음으로 패키지의 동작 방식을 결정했습니다.
- 각 시크릿 파일에 해당하는 새로운 시크릿 파일을 만들 수도 있고, 모든 시크릿 파일을 하나도 묶어버릴 수도 있습니다.
- GPG처럼 비대칭 암호화를 사용할 수도 있고 AES처럼 대칭 암호화를 사용할 수도 있습니다.
- 암호를 직접 공급할 수도 있고 자동생성할 수도 있습니다.
저는 최대한 간단한 사용을 위해
- 모든 시크릿 파일을 하나의 파일로 묶으며
- AES-256 대칭 키 알고리즘을 사용하였고
- 마스터 패스워드는 자동 생성하도록 구현했습니다.
그 외에도 다음과 같은 사항을 고려했습니다.
- 최대한 디펜던시를 줄이기 위해 Node.js의 표준 라이브러리만을 사용했습니다.
- Typescript를 사용하여 오류를 최대한 줄였습니다.
시크릿 파일을 하나의 파일로 묶으면 개발 환경일 때의 시크릿과 프로덕션 환경에서의 시크릿을 각각 다른 파일로 암호화, 필요에 따라 사용할 수 있다는 장점이 있습니다. 또한 마스터 패스워드를 직접 입력하도록 하면 password
등의 너무 간단한 마스터 패스워드를 사용하는 사람들이 있을 것으로 판단하여 무작위 값을 갖는 마스터 패스워드를 생성하도록 구현했습니다.
다만 이렇게 하면 암호화를 할 때마다 다른 마스터 패스워드가 생성되는 번거로움이 있어 나중에 이를 공급할 수 있도록 업데이트할지를 고민중입니다.
구현은 간단하게 .secrets
파일에 암호화할 시크릿 파일들, 예컨대 .env
등을 나열하면 이를 하나의 .secrets.encrypted
파일로 묶도록 구현했습니다.
Coding
개발할 때에는 VSCode의 dev container를 이용하였고 mock-fs
와 jest
를 이용하여 테스트를 구현했습니다. 본 솔루션은 파일시스템에 접근하는데 이런 테스트코드를 한 번도 작성해본 적이 없어 곤란했었습니다. 처음에는 mock-fs
같은 편리한 라이브러리가 있는 줄 모르고 실제 파일시스템을 이용하여 테스트코드를 작성하였는데, 생각한 대로 동작하지 않아서 상당히 곤란했었습니다.
Open Source Publish
이후 이를 다양한 프로젝트에서 사용하고자 NPM에 게시했습니다. 올리고 보니 다른 사람들도 이 패키지를 사용하면 좋겠다는 생각이 들었고, 제대로 된 오픈소스 프로젝트를 한 번 만들어봐야겠다고 생각했습니다.
막상 공개하려고 하니 프로젝트 이름과 로고가 마땅치 않았고, 그래서 자동으로 프로덕트 이름과 로고를 생성해주는 사이트를 통해 Git-Key라는 프로젝트 이름과 그 로고를 생성했습니다. 이후 적절한 documentation을 추가하고 npm에 게시했습니다.
Conclusion
Secret 관리를 도와주는 Git-Key라는 오픈 소스 패키지를 만들고 npm에 게시해봤습니다. 처음으로 제대로 된 오픈 소스 프로젝트를 진행해봤는데, 여러모로 재미있었습니다.