1 개요
SSH 키 관리의 핵심은 “접속을 시작하는 주체” 에 개인키가 있어야 한다는 원칙이다. 로컬 PC, VM 서버, CI/CD 파이프라인이 각각 다른 대상에 접속할 때 필요한 키가 달라진다. 이 원칙을 이해하면 멀티 계정 SSH 충돌 문제도 자연스럽게 해결된다.
- 개발 환경에서 로컬 PC, Azure VM, GitHub Actions가 각각 서로 다른 대상에 SSH로 접속한다.
- 각 접속 주체에 적합한 키를 준비하고,
~/.ssh/config의 Host alias로 멀티 계정을 명확히 구분한다.
2 SSH 키의 핵심 원칙
SSH에서 접속을 시작하는 쪽(클라이언트) 에 개인키(private key)가 있어야 하고, 접속을 받는 쪽(서버) 에 공개키(public key)가 등록되어 있어야 한다.
클라이언트 (개인키 보유) → SSH 접속 → 서버 (공개키 등록됨)
따라서 어떤 머신이 능동적으로 다른 곳에 접속하면, 그 머신에 개인키가 있어야 한다.
2.1 개인키 파일 형식: .pem vs id_ed25519
id_rsa, id_ed25519 같은 파일만 개인키라고 생각하기 쉽지만, .pem도 형식만 다를 뿐 동일한 개인키다.
| 파일 | 형식 | 발급 주체 |
|---|---|---|
id_ed25519 |
OpenSSH 형식 | 사용자가 ssh-keygen으로 직접 생성 |
test-agent_key.pem |
PEM 형식 | Azure/AWS가 VM 생성 시 발급 |
두 형식 모두 ~/.ssh/config의 IdentityFile에 지정해서 동일하게 사용한다.
2.2 Azure VM 키 페어의 생성 위치
.pem 파일은 VM에서 생성된 것이 아니라, Azure가 생성해서 로컬로 내려준 개인키다.
Azure Portal에서 VM 생성
↓
Azure가 키 페어를 생성
↓
개인키(.pem) → 로컬로 다운로드 ← test-agent_key.pem 이것
공개키 → VM의 ~/.ssh/authorized_keys에 자동 등록
VM 내부에는 공개키만 등록되어 있고 개인키는 없다. 그래서 로컬에서 .pem으로 VM에 접속할 수 있는 것이다. 만약 VM 안에 개인키가 있다면 그건 보안 문제다.
현재 로컬 ~/.ssh/에 id_ed25519 계열 파일이 없더라도, .pem 파일이 있다면 VM 접속용 개인키는 이미 존재하는 것이다. “개인키가 없다”는 표현은 GitHub SSH용 키가 없다는 의미일 뿐이다.
3 환경별 SSH 키 전략
3.1 키 주체별 정리
로컬 PC, VM, GitHub Actions 각각이 어디에 접속하는지에 따라 필요한 키가 결정된다.
| 접속 주체 | 접속 대상 | 키 종류 | 위치 |
|---|---|---|---|
| 로컬 PC | Azure VM | .pem 키 파일 |
로컬 ~/.ssh/ |
| 로컬 PC | GitHub | id_ed25519_* |
로컬 ~/.ssh/ |
| Azure VM | GitHub | id_ed25519 |
VM의 ~/.ssh/ |
| GitHub Actions | Azure VM | .pem 내용 |
GitHub Secrets |
3.2 로컬 PC → Azure VM
Remote-SSH로 VM에 접속할 때 “나는 azureuser다”를 증명하는 키다. 이게 없으면 VM 접속 자체가 불가능하다. Azure에서 VM을 생성할 때 발급받은 .pem 파일이 이 역할을 한다.
3.3 로컬 PC → GitHub
로컬에서 git push, git pull을 SSH로 할 때 필요하다. HTTPS 방식으로 GitHub를 쓰고 있다면 당장은 없어도 되지만, 멀티 계정 설정을 하려면 반드시 필요하다. HTTPS는 URL만으로 계정을 구분할 수 없어서 멀티 계정이 불가능하다.
3.4 Azure VM → GitHub
VM이 GitHub에서 코드를 git pull할 때 필요하다. 배포 스크립트가 아래와 같은 형태라면, VM 자신이 GitHub에 인증해야 한다.
VM에 키가 없으면 이 단계에서 인증이 막힌다.
3.5 GitHub Actions → Azure VM
GitHub Actions가 코드를 빌드한 후 VM에 자동 배포할 때, Actions 서버가 VM에 SSH로 접속해야 한다. .pem 파일의 내용을 GitHub Secrets에 등록해두면 Actions가 그 키로 VM에 접속한다.
# .github/workflows/deploy.yml
- name: Deploy to VM
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.VM_HOST }}
username: azureuser
key: ${{ secrets.VM_SSH_KEY }} # .pem 파일 전체 내용
script: |
docker pull ghcr.io/username/myapp
docker compose up -dCI/CD에서는 개인이 쓰는 범용 키를 그대로 쓰지 않고, 배포 전용 키를 별도로 생성해서 Secrets에 등록하는 것이 보안상 올바르다.
3.6 VM에서 SSH 키를 생성해야 하는 경우 요약
VM 자신이 능동적으로 외부에 접속하는 시나리오에서만 VM에 키가 필요하다.
| 시나리오 | VM에 키 필요 여부 |
|---|---|
| VM → GitHub (코드 pull/push) | 필요 |
| VM → 다른 VM (내부 통신) | 필요 |
| VM → Docker Registry | 필요 |
| CI/CD Runner가 VM에서 실행 | 필요 |
| 내가 로컬에서 VM에 접속만 할 때 | 불필요 |
4 GitHub SSH 멀티 계정이 필요한 경우
GitHub 계정이 1개라면 멀티 계정 설정은 불필요하다. SSH 키도 1개만 만들면 된다.
# GitHub용 SSH 키 하나만 생성 (단일 계정)
ssh-keygen -t ed25519 -C "your@email.com" -f ~/.ssh/id_ed25519_github# config에 추가
Host github.com
HostName github.com
User git
IdentityFile ~/.ssh/id_ed25519_github
개인 프로젝트와 회사 프로젝트를 같은 GitHub 계정으로 관리하고 있다면 이 키 하나로 모두 커버된다.
멀티 계정 SSH 설정이 필요해지는 시점은 회사가 별도 GitHub 조직 계정(또는 GitHub Enterprise)을 만들고 전용 계정을 요구할 때다.
| 상황 | 멀티 계정 필요 여부 |
|---|---|
| 개인 계정 1개로 개인/회사 프로젝트 모두 관리 | 불필요 — 키 1개로 충분 |
| 개인 계정 + 회사 전용 계정 분리 | 필요 |
| 개인 계정 + 여러 조직 계정 | 필요 |
| 개인 계정 + 봇/서비스 계정 | 필요 |
멀티 계정이 필요한 경우 HTTPS보다 SSH가 훨씬 편하다. git credential manager는 계정을 하나만 캐싱해서 다른 계정 repo에 push할 때마다 로그인을 다시 해야 하는 반면, SSH alias는 URL만으로 계정을 구분해 비밀번호 입력 없이 자동 인증된다.
5 문제 상황: 멀티 계정 SSH 충돌
5.1 기본 SSH 접속 시도
GitHub은 기본적으로 ~/.ssh/id_rsa 또는 ~/.ssh/id_ed25519 키를 시도한다. SSH 키가 여러 개 있을 때 어떤 키를 써야 할지 특정할 수 없어서 인증이 실패한다.
조직/팀별로 별도 키를 쓸 경우 ~/.ssh/config로 alias를 지정해야 인증 충돌을 방지할 수 있다.
5.2 VM 서버의 SSH 키 현황 예시
$ ls ~/.ssh/*.pub
/home/azureuser/.ssh/agent_repo.pub # 개인 repo용 키
/home/azureuser/.ssh/sg_org.pub # 조직(Seegene) repo용 키두 개의 키가 각각 다른 GitHub 계정/조직에 등록되어 있는 상태에서, 기본 접속으로는 어떤 키를 써야 할지 알 수 없다.
6 ~/.ssh/config 구조
SSH config 파일은 여러 계정/조직별로 Host alias를 지정해, 각 alias마다 사용할 키와 접속 정보를 분리 관리한다. 실무에서는 개인/조직/CI용 키를 모두 별도 alias로 관리하는 것이 안전하다.
Host agent_repo
HostName github.com
User git
IdentityFile ~/.ssh/agent_repo
Host seegene_org
HostName github.com
User git
IdentityFile ~/.ssh/seegene_org
6.1 설정 항목 설명
| 항목 | 설명 |
|---|---|
Host |
SSH 접속 시 사용할 alias (임의 이름) |
HostName |
실제 접속할 호스트 (github.com) |
User |
GitHub SSH 접속 유저 (항상 git) |
IdentityFile |
이 alias 사용 시 적용할 SSH private key 경로 |
7 alias를 사용한 접속 테스트
SSH alias로 접속하면 원하는 키로 인증이 명확히 이뤄진다. 실무에서는 인증 테스트를 통해 키/alias 설정이 올바른지 반드시 확인한다.
$ ssh -T git@seegene_org
Hi kmkim-seegene! You've successfully authenticated,
but GitHub does not provide shell access.git@seegene_org는 실제로 git@github.com으로 접속하되 ~/.ssh/seegene_org 키를 사용한다.
“does not provide shell access” 는 정상이다. GitHub SSH는 shell이 아닌 git 명령만 허용하므로 인증 성공 메시지다.
8 git clone/remote URL에서 alias 사용
git clone, remote 등 모든 git 명령에서 github.com 대신 SSH alias를 쓰면, ~/.ssh/config에 지정한 키로 자동 인증된다. 여러 계정/조직을 병행 관리할 때 필수적인 패턴이다.
8.1 일반 GitHub URL vs alias URL
# 기본 URL (어떤 키를 쓸지 모름)
git clone git@github.com:SeegeneDevelopmentPlatform/repo.git
# alias URL (seegene_org 키 사용 명시)
git clone git@seegene_org:SeegeneDevelopmentPlatform/repo.gitgithub.com 대신 alias 이름(seegene_org)을 사용하면 ~/.ssh/config에 따라 올바른 키로 자동 인증된다.
9 Poetry git dependency에서 alias 사용
Poetry, pip 등 Python 패키지 관리 도구에서도 SSH alias를 그대로 활용할 수 있다. pyproject.toml에 기록되는 URL에도 alias를 쓰면, 팀 전체가 동일한 인증 구조를 공유할 수 있다. 단, 팀원 모두 동일한 alias 설정이 필요하다.
SSH alias는 poetry add 명령과 pyproject.toml URL에도 동일하게 적용된다.
# 기본 github.com — 어떤 키를 쓸지 불명확, 인증 실패 가능
poetry add "git+ssh://git@github.com/SeegeneDevelopmentPlatform/repo.git@main"
# alias 사용 — seegene_org 키로 명확하게 인증
poetry add "git+ssh://git@seegene_org/SeegeneDevelopmentPlatform/repo.git@main"pyproject.toml에 기록되는 형태:
[project]
dependencies = [
"sg-data-standardization @ git+ssh://git@seegene_org/SeegeneDevelopmentPlatform/data_standardization.git@main"
]이 pyproject.toml을 다른 팀원이 사용하려면 해당 팀원의 ~/.ssh/config에도 동일한 seegene_org alias가 설정되어 있어야 한다.
10 특정 키를 일회성으로 지정 — GIT_SSH_COMMAND
SSH config를 수정하지 않고 임시로 특정 키만 지정해 git 명령을 실행할 수도 있다.
GIT_SSH_COMMAND환경변수는 일회성 인증, 임시 테스트, CI/CD 등에서 유용하다.
config를 수정하지 않고 임시로 특정 키를 사용하는 방법:
GIT_SSH_COMMAND='ssh -i ~/.ssh/seegene_org -o IdentitiesOnly=yes' \
git clone git@github.com:org/repo.git| 옵션 | 설명 |
|---|---|
-i ~/.ssh/seegene_org |
사용할 private key 경로 |
-o IdentitiesOnly=yes |
지정한 키만 사용 (ssh-agent 키 무시) |
11 최종 ~/.ssh/config 구성 예시
로컬 PC 기준으로 VM 접속과 멀티 GitHub 계정을 모두 포함한 완성된 config 형태다.
# Azure VM 접속
Host ai_agent_dev_vm
HostName 20.196.196.16
User azureuser
Port 22
IdentityFile ~/.ssh/vm_key.pem
# GitHub 개인 계정
Host github-personal
HostName github.com
User git
IdentityFile ~/.ssh/id_ed25519_personal
# GitHub 조직/회사 계정
Host github-work
HostName github.com
User git
IdentityFile ~/.ssh/id_ed25519_work
이 구성에서 각 접속 방식은 아래와 같다:
12 SSH 키 생성 및 GitHub 등록 전체 흐름
SSH 키 생성, 공개키 등록, config alias 추가, 인증 테스트까지의 전체 흐름은 실무에서 반복적으로 사용되는 기본 패턴이다.
12.1 Step 1: 키 생성
ed25519 알고리즘을 권장한다. 기존 rsa 방식보다 짧고 보안성이 높다.
| 옵션 | 설명 |
|---|---|
-t ed25519 |
키 알고리즘 (ed25519 권장) |
-C "your@email.com" |
키에 붙이는 주석 (GitHub 이메일 사용) |
-f 경로 |
키 파일 저장 경로 (생략 시 기본값 ~/.ssh/id_ed25519) |
명령 실행 후 passphrase 입력을 요구한다. 빈칸으로 두면 패스프레이즈 없이 사용할 수 있다 (편의성↑, 보안↓). 실무에서는 설정을 권장한다.
생성 결과:
~/.ssh/id_ed25519_work ← 개인키 (절대 유출 금지)
~/.ssh/id_ed25519_work.pub ← 공개키 (GitHub에 등록할 것)
개인키(id_ed25519_work)는 절대 외부에 공유하거나 git에 커밋하지 않는다. 공개키(.pub)만 외부에 등록한다.
키 생성 시 터미널에 아래와 같이 출력된다:
Your identification has been saved in ~/.ssh/id_ed25519_work
Your public key has been saved in ~/.ssh/id_ed25519_work.pub
The key fingerprint is:
SHA256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx your@email.com
The key's randomart image is:
+--[ED25519 256]--+
| .o+. |
...
+----[SHA256]-----+
fingerprint와 randomart는 따로 저장할 필요 없다. 언제든 재확인할 수 있다:
12.2 Step 2: GitHub에 공개키 등록
공개키를 클립보드로 복사한다.
Linux/macOS:
Windows(PowerShell):
GitHub 등록 절차:
- GitHub 로그인 → 우측 상단 프로필 아이콘 → Settings
- 좌측 메뉴 → SSH and GPG keys
- New SSH key 클릭
- Title: 키를 구분할 이름 입력 (예:
work-laptop-2026) - Key type:
Authentication Key(기본값) - Key: 클립보드 붙여넣기
- Add SSH key 클릭
12.3 Step 3: ~/.ssh/config에 alias 추가
cat >> ~/.ssh/config << 'EOF'
Host github-work
HostName github.com
User git
IdentityFile ~/.ssh/id_ed25519_work
EOF멀티 계정이 아닌 단일 계정이라면 Host github.com으로 그대로 사용하면 된다.
12.4 Step 4: 인증 테스트
처음 접속 시 known_hosts 추가 여부를 묻는다. yes를 입력한다:
The authenticity of host 'github.com (140.82.121.4)' can't be established.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
인증 성공 시 출력:
Hi kmink3225! You've successfully authenticated,
but GitHub does not provide shell access.
but GitHub does not provide shell access.는 오류가 아니라 정상이다. GitHub SSH는 shell 접속이 아닌 git 명령만 허용하기 때문이다.
12.5 최종 ~/.ssh/ 디렉토리 상태
~/.ssh/
├── config ← Host alias 설정 파일
├── id_ed25519_work ← 조직 계정 개인키
├── id_ed25519_work.pub ← 조직 계정 공개키
├── id_ed25519_personal ← 개인 계정 개인키 (멀티 계정 시)
├── id_ed25519_personal.pub ← 개인 계정 공개키 (멀티 계정 시)
├── known_hosts ← 신뢰한 서버 목록 (자동 생성)
└── vm_key.pem ← Azure VM 접속용 개인키 (있는 경우)
13 요약
| 항목 | 내용 |
|---|---|
| SSH 키 핵심 원칙 | 접속을 시작하는 주체에 개인키가 있어야 한다 |
기본 git@github.com 실패 원인 |
여러 키 중 어떤 키를 써야 할지 특정 불가 |
| 해결 방법 | ~/.ssh/config에 Host alias 정의 |
| alias 형식 (git) | git@alias_name:org/repo.git |
| alias 형식 (Poetry) | git+ssh://git@alias_name/org/repo.git@branch |
| VM에 키가 필요한 경우 | VM이 GitHub, 다른 VM 등 외부에 능동적으로 접속할 때 |
| CI/CD 배포 키 | 범용 개인키 대신 전용 배포 키를 별도 생성해 Secrets에 등록 |
| 팀 공유 시 주의 | 모든 팀원이 동일한 alias 설정 필요 |
다음 블로그에서는 pyproject.toml이 없는 repo를 패키지화하기 위해 setuptools 설정 파일을 작성하고 PR로 반영하는 과정을 다룬다.