Agent 연결
이 문서는 Deplite의 인증·통신 흐름을 정확히 이해하고 싶을 때 읽으면 좋아요.
운영에 꼭 필요한 내용은 아니지만, 보안 검토나 트러블슈팅 시 큰 도움이 돼요.
전체 흐름
[1] Enrollment (1회)
Agent → POST /agent/enroll (Bearer <enr_...>)
← { agentId, serverPublicKey }
Agent 로컬: agent.id / agent.key / server.pub 저장
[2] 상시 연결
Agent → GET /agent/stream (SSE, 서명 헤더)
⇐ deploy / workflows-refresh / revoke / ping
[3] 주기 작업
Agent → POST /agent/heartbeat (60초마다)
Agent → POST /agent/workflows/report (변경 감지 시)
[4] Job 실행 시
Server (SSE) → "deploy" event (ED25519 서명된 payload)
Agent → POST /agent/jobs/:id/logs (JSONL, 64KB·1초 배치)
Agent → POST /agent/jobs/:id/resultEnrollment
최초 1회만 발생해요.
POST /agent/enroll
Authorization: Bearer enr_...
Content-Type: application/json
{
"name": "my-agent",
"publicKey": "-----BEGIN PUBLIC KEY-----\n...",
"hostname": "prod-01",
"os": "linux",
"agentVersion": "0.2.0"
}서버는 agentId와 자신의 ED25519 serverPublicKey를 돌려줘요.
Agent는 이걸 받아서 ./creds/에 영구 저장하고, 이후엔 Enrollment Token이 더 이상 필요하지 않아요.
요청 서명 (Agent → Server)
Enrollment 이후 Agent가 서버로 보내는 모든 요청은 ED25519로 서명돼요.
X-Agent-Id: <agentId>
X-Timestamp: 1717180800
X-Nonce: <16 bytes hex>
X-Signature: <base64 ed25519 signature>서명 대상(canonical string)은 다음과 같아요.
<timestamp>
<nonce>
<UPPERCASE-METHOD>
<path-with-query>
<sha256-hex-of-body>서버는 다음을 검증해요.
X-Timestamp가 현재 시각 ±60초 범위인가X-Nonce가 LRU 캐시(TTL 10분)에 없는가 (재생 공격 방지)- 서명이 Agent의 등록된 공개키로 검증되는가
SSE 이벤트
GET /agent/stream
(요청 서명 헤더 + Accept: text/event-stream)서버는 다음 종류의 SSE 이벤트를 보내요.
| 이벤트 | 의미 |
|---|---|
deploy | 워크플로우 실행 명령. payload는 ED25519 서명된 CommandPayload JSON |
workflows-refresh | 즉시 워크플로우 디렉토리를 재스캔 |
revoke | 이 Agent가 회수됨. 즉시 종료 |
ping | 연결 유지 신호 |
SSE 연결이 끊기면 Agent는 1초→2초→4초… 60초까지 지수 백오프로 재연결을 시도해요.
30초 동안 어떤 이벤트도 안 오면 유휴로 보고 강제 재연결해요.
Deploy 명령 검증 (Server → Agent)
{
"payload": "<base64-json>",
"signature": "<base64-ed25519>"
}Agent는 다음을 확인해요.
- payload base64 디코딩 후 JSON 정규화 (정렬된 키)
server.pub로 ED25519 검증issued_at이 현재 시각 ±60초인가nonce가 자체 LRU 캐시에 없는가
검증을 통과해야만 실제 워크플로우가 실행돼요.
Heartbeat
POST /agent/heartbeat
{
"agent_version": "0.2.0",
"running_jobs": ["job-id-1"],
"workflow_count": 5
}60초 주기로 보내요.
대시보드의 Agent 상태(connected/disconnected)는 이걸로 갱신돼요.
워크플로우 보고
POST /agent/workflows/report
{
"workflows": [
{ "name": "deploy-prod", "verboseSteps": ["build"], "secretsKeys": ["DB_URL"] }
]
}서버에는 워크플로우 메타데이터만(이름, verbose step 목록, 시크릿 키 이름) 보고돼요.
실제 YAML 내용·step 명령어·시크릿 값은 서버로 가지 않아요.
회수(Revoke)
대시보드에서 Agent를 revoke하거나, SSE revoke 이벤트를 받으면 Agent는 즉시 종료해요.
이후 같은 agent.key로는 재연결할 수 없어요. 새 Enrollment Token으로 다시 등록해야 해요.