호스팅 콘솔을 만들며 가장 조심스러웠던 데이터가 하나 있습니다. 고객 서버에 접속하는 SSH 개인 키입니다. 이 키는 비밀번호와 성격이 다릅니다. 비밀번호는 해시로 바꿔 저장하고 원본을 버려도 되지만 SSH 개인 키는 고객이 실제로 서버에 접속하려면 원본 그대로가 필요합니다. 되돌릴 수 있는 형태로 보관하되 절대 평문으로 두어서는 안 되는 데이터입니다. 자체 서비스인 콘솔에서 이 키를 어떻게 다뤘는지 정리합니다.
왜 해시가 아니라 암호화인가
비밀번호를 다룰 때는 단방향 해시를 씁니다. 저장한 값에서 원본을 되돌릴 수 없어야 안전하고 로그인 때는 입력값을 같은 방식으로 해시해 비교만 하면 됩니다. 하지만 SSH 개인 키에는 이 방식이 통하지 않습니다. AWS가 인스턴스를 만들 때 발급한 키페어의 개인 키는 고객이 나중에 서버에 접속할 때 원본 그대로 다시 꺼내 써야 합니다. 되돌릴 수 없는 해시로 바꿔 버리면 고객이 자기 서버에 들어갈 방법이 사라집니다.
그래서 선택한 것이 양방향 암호화입니다. 되돌릴 수 있되 열쇠를 가진 쪽만 되돌릴 수 있는 방식입니다. 알고리즘은 AES-256-GCM을 골랐습니다. GCM 모드를 고른 이유는 암호화만 하는 것이 아니라 데이터가 중간에 변조되지 않았는지까지 검증해 주기 때문입니다. 누군가 저장된 값을 조금이라도 바꾸면 복호화 단계에서 그 사실이 드러납니다.
키가 만들어지는 순간 바로 암호화한다
가장 중요한 원칙은 평문 개인 키가 시스템 안에 머무는 시간을 최소로 줄이는 것이었습니다. 프로비저닝 과정에서 AWS에 키페어 생성을 요청하면 그 응답에 개인 키의 원본이 담겨 돌아옵니다. 이 원본이 손에 들어온 바로 다음 줄에서 암호화합니다. 데이터베이스에 저장되는 시점에는 이미 암호화된 문자열이고 평문은 어디에도 기록되지 않습니다.
암호화한 결과는 세 조각을 이어 붙인 문자열로 저장합니다. 암호화할 때마다 새로 만드는 초기화 벡터, 변조 검증에 쓰이는 인증 태그, 그리고 실제 암호문입니다. 이 셋을 각각 인코딩해 구분자로 이어 붙여 한 칸에 담습니다. 복호화할 때는 이 문자열을 다시 세 조각으로 나눠 초기화 벡터와 인증 태그를 복원하고 암호문을 원래 키로 되돌립니다. 만약 저장된 값의 형식이 깨졌거나 인증 태그가 맞지 않으면 복호화가 실패하며 잘못된 데이터를 조용히 넘기지 않습니다.
암호화에 쓰는 비밀 열쇠는 코드에 박아 두지 않고 환경 변수로 주입합니다. 이 열쇠가 충분히 길지 않으면 시스템이 아예 시작 단계에서 오류를 내도록 했습니다. 짧고 약한 열쇠로 조용히 돌아가다가 나중에 문제가 되는 것보다, 처음부터 제대로 된 열쇠가 없으면 멈추는 편이 안전하기 때문입니다.
전달은 한 번, 그리고 기록으로 남긴다
암호화해 저장한 키는 고객이 서버를 받을 때 딱 한 번 복호화해 전달합니다. 평소에는 데이터베이스 안에서 암호문으로만 존재하고 고객에게 내려보내는 그 순간에만 원래 키로 되돌립니다. 고객이 키를 실제로 내려받았는지 여부를 별도로 기록합니다. 누가 키를 이미 받아 갔는지 추적할 수 있어야 재발급이나 문의 대응에서 판단 근거가 되기 때문입니다.
이 설계에는 분명한 절충이 있습니다. 개인 키를 우리 쪽 데이터베이스에 보관한다는 것 자체가 부담이라는 지적은 타당합니다. 가장 이상적인 방식은 개인 키를 서버에 절대 남기지 않고 고객이 생성 시점에만 받아 가도록 하는 것입니다. 다만 자동 프로비저닝과 사후 전달, 재다운로드 대응이라는 운영 요구를 만족시키려면 어느 시점까지는 되돌릴 수 있는 형태로 보관해야 했습니다. 그 대신 평문 노출을 최소화하고 변조를 검증하며 열쇠를 코드에서 분리하는 방어를 겹쳐 두었습니다. 앞으로는 전용 비밀 관리 서비스로 키 자체를 옮겨 보관 부담을 더 줄이는 방향을 열어 두었습니다.
정리하며
되돌릴 수 있어야 하는 비밀은 비밀번호와 다르게 다뤄야 합니다. 해시가 아니라 암호화를 쓰되, 평문이 머무는 시간을 극단적으로 줄이고, 변조를 검증하는 모드를 고르고, 열쇠를 코드에서 떼어 내는 것. 화려하지 않지만 남의 서버 열쇠를 맡아 두는 일에서는 이 기본기가 전부입니다.
이 키가 만들어지는 프로비저닝 시퀀스 전체는 EC2 자동 프로비저닝을 백그라운드 워커로에서, 콘솔의 전체 구조는 SaaS 운영 콘솔 구축기에서 볼 수 있습니다.
자주 묻는 질문
SSH 키도 비밀번호처럼 해시로 저장하면 되지 않나요?
안 됩니다. 비밀번호는 되돌릴 수 없는 해시로 바꿔도 로그인 때 비교만 하면 되지만 SSH 개인 키는 고객이 서버에 접속할 때 원본 그대로 다시 필요합니다. 그래서 되돌릴 수 있는 양방향 암호화를 쓰되 열쇠를 가진 쪽만 복호화할 수 있게 했습니다.
왜 AES-256-GCM을 골랐나요?
GCM 모드는 데이터를 암호화하는 동시에 변조 여부까지 검증해 줍니다. 누군가 저장된 값을 조금이라도 바꾸면 복호화 단계에서 인증 태그가 맞지 않아 실패합니다. 암호문과 함께 초기화 벡터, 인증 태그를 묶어 저장하고 복호화 때 이를 검증하는 방식으로 데이터 무결성까지 확보했습니다.
개인 키를 서버에 보관하는 것 자체가 위험하지 않나요?
맞는 지적입니다. 그래서 평문이 머무는 시간을 최소로 줄이고, AWS가 키를 돌려준 즉시 암호화하며, 암호화 열쇠는 코드가 아니라 환경 변수로 분리했습니다. 그럼에도 보관 자체가 부담인 것은 사실이라, 전용 비밀 관리 서비스로 키를 옮겨 보관 부담을 더 줄이는 방향을 다음 과제로 열어 두었습니다.