안전하게 ssh 키를 관리해보자
🔑

안전하게 ssh 키를 관리해보자

Published
August 3, 2025
Tags
ssh
security

개요

개발을 진행하면서 다양한 툴과 서비스에 대한 암호 관리는 항상 어려운 주제였다. 알면서 방치하는 보안 취약점이라고 생각은 했으나, 팀원들과 빠르게 공유하기 위해서 사내 메신저나 위키에 텍스트로 보관하는 경우가 많았다. 그리고 사고는 한 순간에 일어났다.
이후에 비밀번호 보안이 필수라고 생각하여 개인적으로 1Password를 구독하게 되었다. 산발적으로 크롬이나 갤럭시, iOS 등에서 따로 관리되던 비밀번호를 한 곳에서 일관되게 관리할 수 있었고, 브라우저 레벨이 아닌 시스템 레벨에서 다양한 형태로 사용할 수 있었다. 사내에서는 가급적 Vaultwarden을 통해서 무료로라도 비밀번호를 관리하고, 안전하게 공유하도록 하였다.
여기서 주목할 만한 점은, SSH 비밀키도 일종의 암호이므로 1Password와 Bitwarden에서 이러한 비밀키를 관리할 수 있는 기능을 제공한다는 것이다. 둘 모두 SSH의 인증을 위한 소켓 프로토콜을 제공하고 있어서, 이를 이용하여 인증 행위를 다른 프로그램으로 넘길 수 있다. 그러면 비밀키를 로컬 디스크에 보관하지 않고도 비밀번호 관리툴을 통해서 안전하게 인증할 수 있는 것이다. 이처럼 SSH의 크레덴셜을 별도로 보관하며 인증을 대신해주는 프로그램을 통상 SSH Agent 라고 부른다.

SSH Agent

다음과 같은 일반적인 SSH 사용 예시를 살펴보자.
ssh username@host -i ~/.ssh/private-key.pem
SSH 프로그램을 사용하지 않는다면 username, host를 외워야하고 키가 디스크에 존재해야 한다. 물론 SSH를 제공하는 다양한 프로그램에서 자체적으로 호스트 관리를 진행할 수도 있지만, 그럼에도 불구하고 키는 항상 프로그램에 등록이 되어있어야 한다. PC가 바뀐다면 늘 곤란한 부분이기도 하다.
이제 위 사용 예시를 조금만 고도화해서 설정 파일에 미리 호스트를 등록해두고 사용해보자.
Host host HostName 192.168.0.2 User username IdentityFile ~/.ssh/private-key.pem
~/.ssh/config
ssh host
많이 간편해졌다.
이제 1Password와 Bitbucket을 사용해보자.

1Password

먼저 1Password를 설치하자.
brew install 1password
설치 후에는 설정 메뉴에서 SSH 에이전트 사용을 체크하도록 하자.
notion image
그리고 1Password에서 사용할 SSH 비밀키를 등록한다.
notion image

Bitwarden

먼저 Bitwarden을 설치하자. Vaultwarden은 별도의 클라이언트가 없고, Bitwarden 클라이언트를 함께 사용하도록 개발되었다.
brew install bitwarden
설치 후에는 설정 메뉴에서 SSH 에이전트 사용을 헤크하도록 하자.
notion image
마찬가지로 필요한 비밀키를 동록해둔다. 1Password와 다르게 기존 키를 가져오기가 약간 까다롭다.
BitwardenBitwardenBitwarden SSH Agent | Bitwarden
notion image
⚠️
Bitwarden에는 다음과 같은 제약이 있다.
  • 조직 내의 SSH 키는 현재 인식이 되지 않는다.
  • 키 타입은 ED25519만 지원한다.

위의 두 프로그램이 모두 설치되었다고 가정하면, 각각의 소켓 위치는 다음과 같다.
1Password: ~/Library/Group Containers/2BUA8C4S2C.com.1password/t/agent.sock Bitbucket: ~/.bitwarden-ssh-agent.sock
보다시피 1Password의 소켓 경로가 복잡하므로, 링크를 생성해서 단순하게 만들면 사용에 좀 더 용이하다.
ln -s ~/Library/Group\ Containers/2BUA8C4S2C.com.1password/t/agent.sock ~/.1p.sock
이제 로컬에 존재했던 모든 비밀키는 비밀번호 관리자로 옮겨졌을 것이고, 기존 SSH 설정에서 비밀번호 관리자로 SSH Agent를 설정하여 인증이 가능하도록 연결해줘야 한다.
Host host-with-1p HostName 192.168.0.2 User username IdentityAgent ~/.1p.sock IdentityFile ~/.ssh/1p.pub Host host-with-bitwarden HostName 192.168.0.3 User username IdentityAgent ~/.bitwarden-ssh-agent.sock IdentityFile ~/.ssh/bitwarden.pub
~/.ssh/config
IdentityAgent 에 각각의 SSH Agent 소켓 위치를 입력하고, IdentityFile 에 각각의 비밀키에 대응하는 공개키 위치를 입력한다. 비밀키를 비밀번호 관리자에 등록하거나 생성하면 여기에서 공개키를 내려받을 수 있는데, 이걸 내려받아서 공개키 경로를 지정해주면 된다.
사실 공개키는 필수로 등록해야 하는 요소는 아니지만, 공개키를 지정하지 않으면 모든 비밀키를 순회하면서 인증을 시도하는 문제가 있다. 그리고 대부분의 SSH 서버는 6회의 시도 후에도 실패하면 자동으로 인증이 차단되기 때문에 이러한 문제를 방지하려면 명시적으로 공개키를 제공하여 이러한 공개키 값을 가지는 비밀키를 사용하라고 알려주어야 한다.
실제로 위 설정을 적용한 본인의 예시 파일은 다음과 같다. 실 사용 예시에서는 다양한 ProxyCommand와 조합되어 방화벽 오픈 없이도 여러 서비스에 접근할 수 있도록 클라우드 공급자의 터널을 최대한 활용하였다.
Host proxmox-docker HostName 172.30.1.95 User root IdentityAgent ~/.1p.sock IdentityFile ~/.ssh/proxmox-docker.pub IdentitiesOnly yes Host mini-ssh.daeho.ro ProxyCommand /opt/homebrew/bin/cloudflared access ssh --hostname %h IdentityAgent ~/.1p.sock IdentityFile ~/.ssh/mini-ssh.pub IdentitiesOnly yes Host jupiter-ssh HostName 172.30.1.11 User username IdentityAgent ~/.bitwarden-ssh-agent.sock IdentityFile ~/.ssh/jupiter.pub IdentitiesOnly yes Host wordpress HostName i-046ac5141b8dc0f68 User bitnami ProxyCommand zsh -c "aws-vault exec lamanus -- aws ssm start-session --target %h --document-name AWS-StartSSHSession --parameters 'portNumber=%p'" IdentityAgent ~/.1p.sock IdentityFile ~/.ssh/wordpress.pub IdentitiesOnly yes Host project-backend HostName dev-instance-backend User daeho.ro ProxyCommand zsh -c "gcloud compute ssh --plain --zone asia-northeast3-c --project project %h" IdentityAgent ~/.bitwarden-ssh-agent.sock IdentityFile ~/.ssh/dev-backend.pub IdentitiesOnly yes
~/.ssh/config

이제 SSH 기능을 테스트 해보도록 하자. 아래 명령을 실행하면 1Password로 연결되고, 거기에서 비밀키를 가져오기 위해서 지문 인증을 요구할 것이다.
ssh wordpress
특히, 이 경우에는 AWS의 SSM 기능을 이용해서 SSH 세션을 열고 있는데, aws-vault 명령을 통해서 안전하게 AWS 크레덴셜을 사용하면서 키체인 접근을 위한 암호 입력을 요구한다.
  • aws-vault 의 키체인 접근 요청 - 암호
  • 크레덴셜이 없으면 AWS의 SSO 로그인 및 권한 인증 요청
  • AWS 크레덴셜 확보 후에는 SSH 비밀키 접근을 위한 1Password 인증 요청
notion image
마찬가지로 다음 명령을 실행하면 Bitwarden에서 비밀키를 가져오기 위해서 인증을 요구할 것이다.
ssh jupiter-ssh
notion image
GCP 기능을 사용하는 경우에도 유사한 방법으로 인증이 진행된다.
ssh project-backend
  • gcloud 크레덴셜이 없다고 오류가 발생
  • gcloud auth login 실행하여 GCP 권한 획득
  • GCP 크레덴셜 확보 후에는 SSH 비밀키 접근을 위한 Bitwarden 인증 요청
이처럼 다양한 서버 접근 환경에서 SSH 비밀키를 안전하게 사용하는 방법에 대해서 살펴보았다. 이 밖에도 SSH는 git 프로토콜에서 많이 쓰이는데, 이번에는 git 설정과 함께 안전하게 비밀키를 사용하는 방법을 알아보자.

Git

흔히 VCS (Version Control System)라고 부르는 시스템의 대표적인 서비스가 바로 Git이다. 많은 곳에서 https 프로토콜을 제공하여 소스를 다운로드하기는 하지만, 권한 인증을 위해서는 별도의 토큰을 발행하거나 위험하게 사용자 이름과 암호를 사용해야 하는 이유로 git 프로토콜은 SSH 인증 방식을 이용한다. 사전에 사용자의 계정에 등록해놓은 SSH 공개키를 기반으로 로컬에서 비밀키를 통해 사용자 인증을 진행하고 권한을 취득하는 것이다.
앞서와 마찬가지로, SSH 비밀키를 사용하기 때문에 동일한 방법으로 비밀번호 관리자를 통한 SSH 비밀키 인증이 가능하다. 다만, 세세한 GitHub 리포지토리별 컨트롤을 위해서는 Git 설정이 꽤 필요하다. 일단 다음 설정을 추가하여 SSH Agent를 사용하도록 설정하자.
Host github.com gitlab.com bitbucket.org IdentityAgent ~/.1p.sock
~/.ssh/config
세 곳의 호스트 모두에 대해서 1Password에 연결되었기 때문에, 모든 git의 origin 관련 동작에서 SSH 비밀키 인증을 1Password가 대신하게 된다. 마냥 편하고 단순해보이지만, 여기에는 약간의 문제가 있다. 바로 계정 구분이나 SSH Agent 분리가 안된다는 것이다. 이러한 세부 작업을 위해서는 SSH 설정과 Git 설정을 모두 진행해야 한다. 조금 번거롭기는 하지만, 한 번 설정해두면 꽤 유용하게 오래도록 쓸 수 있으므로 설정을 고려해보자.

SSH 설정

먼저 다음과 같은 2가지 경우의 사용 사례를 생각해보자.
  • GitHub 계정이 2개 이상인 경우
  • GitHub 회사 조직에서 별도의 SSH 비밀키를 사용해야 하는 경우
두 경우 모두 SSH의 호스트 설정으로는 분리가 어려워보인다. 그래서 이런 경우에는 호스트 자체를 커스텀해서 해결할 수 있다. 일반적으로 GitHub의 호스트는 git@github.com 으로 고정되어 있다. 그러면 리포지토리 주소는 다음과 같다.
git@github.com:user-or-org/repo.git
github example
이때 호스트 영역을 편집해서 origin으로 등록하고, SSH 설정에서 편집된 호스트별로 Agent를 분리하거나, 별도의 비밀키를 사용하도록 공개키 등록을 해주면 된다.
Host github.com gitlab.com bitbucket.org IdentityAgent ~/.1p.sock Host github-org HostName github.com User git IdentityAgent ~/.bitwarden-ssh-agent.sock IdentityFile ~/.ssh/organization.pub IdentitiesOnly yes
~/.ssh/config
그러면 일반적인 GitHub 리포는 기존과 동일하게 등록을 하고 1Password 인증을 받고, 조직의 리포는 등록할 때, git@github.comgithub-org으로 호스트를 다르게 등록하여 인증 프로세스를 분리할 수 있다! 매번 origin을 편집해야 하는 부분은 귀찮을 수 있지만, 개인과 업무가 완전히 분리가 가능하다는 장점이 있다. 이처럼 호스트를 편집함으로써 원하는 대부분의 구현이 가능하다.

Git 설정

위와 같은 사용 사례는 굉장히 복잡한 조건을 만족하기 위한 경우로 한정된다. 만약, 계정이 여러개여도 같은 비밀키를 사용한다면 굳이 호스트를 조작할 필요는 없다. 다만, GitHub의 조직이나 개인 리포를 구분하여 거기에서 사용될 키가 어떤 키인지는 알려줘야 한다.
SSH 설정은 기존처럼 유지하고, Git 설정을 진행해보자.
기존의 글을 간단히 요약하자면, ~/.gitconfig 설정을 통해서 remote의 주소 형태에 따른 설정 분리가 가능하고, 이를 위해서는 다음과 같이 설정을 진행하면 된다는 것이다.
... [includeIf "hasconfig:remote.*.url:git@github.com:org1/**"] path = ~/.config/git/config-work [includeIf "hasconfig:remote.*.url:git@github.com:org2/**"] path = ~/.config/git/config-work-2
~/.gitconfig
그러면 각각의 추가 설정 파일에서 SSH 공개키를 다르게 지정함으로써 리포지토리별로 서로 다른 키를 사용할 수도, 같은 키를 사용할 수도 있는 것이다. 그리고 이러한 공개키 설정이 되어있다면, SSH Agent를 통해서 인증하기 때문에 안전하게 비밀키를 보관하면서 사용할 수 있다.
이와 더불어, Git 설정은 url 을 이용하여 분리했기 때문에, SSH 설정에서 호스트를 변경했다면 이에 맞춰서 Git에서도 호스트를 변경해주면 된다. 그러면 원하는 무한대의 조합으로 계정, 조직, 리포지토리, SSH Agent를 모두 구분할 수 있게 될 것이다.

맺음말

이번 글에서는 비밀번호 관리자를 사용하여 SSH 비밀키를 안전하게 보관하고, 사용하는 방법에 대해서 알아보았다. 누군가는 왜 SSH 프로그램을 사용하지 않고, 복잡하게 관리하는지 궁금해할 수 있다. 그리고 이 모든것의 목적은 바로 dotfiles를 별도로 관리하기 위함이다.
지금까지 모든 설정은 사용자의 홈 경로 하위에서 이루어졌고, 이제 dotfiles를 관리하는 별도의 프로그램을 통해서 위의 모든 설정들을 별도로 Git 리포지토리를 통해서 관리할 수 있다. 그러면 사용하는 컴퓨터가 바뀌어도, 포맷을 해도 설정을 손쉽게 복구, 이전, 관리할 수 있으며 언제나 동일한 개발 환경을 유지하는데 도움이 된다.
dotfiles 관리 방법에 대해서는 별도의 글을 통해서 소개하도록 하고, 이번 글은 여기서 마친다.

참고 자료

  • AWS Systems ManagerAWS Systems Manager8단계: (선택 사항) Session Manager를 통한 SSH 연결에 대한 권한 허용 및 제어 - AWS Systems Manager