본문으로 건너뛰기

Client Node (Docker) 사용 가이드

ABC WaaS Client Node는 MPC 기반 지갑의 키쉐어 생성, 복구, 서명 기능을 서버 사이드에서 사용할 수 있도록 제공합니다. Client Node는 Docker 이미지로 제공되며, 고객사 백엔드 환경에 배포하여 REST API로 호출합니다.

서비스 이용을 위해서는 유효한 Access Token이 필요합니다. Access Token은 고객사 백엔드에서 WaaS v3 인증 API를 통해 발급받은 후, Client Node API 호출 시 Authorization: Bearer <access_token> 헤더로 전달합니다.


아키텍처

Client Node는 자체적으로 키 데이터를 저장하지 않는 Stateless 구조입니다. 모든 통신은 ABC WaaS Gateway를 경유하므로, 고객 환경에서는 WAAS_API_URL 하나만 설정하면 됩니다.


준비물

배포에 앞서 ABC로부터 다음 정보를 제공받아야 합니다.

항목설명
Docker 이미지ghcr.io/ahnlabio/abc-mpc-client-node-customer:<tag> (GitHub Container Registry public)
WAAS_API_URLhttps://api.waas.myabcwallet.com
Access Token 발급 방법WaaS v3 인증 API 사용 가이드

설치

Docker 이미지 받기

Docker 이미지는 GitHub Container Registry (ghcr.io) 에서 public으로 제공됩니다. 별도 인증 없이 바로 pull 할 수 있습니다.

배포 저장소: https://github.com/ahnlabio/abc-mpc-client-node-customer

패키지 페이지: https://github.com/ahnlabio/abc-mpc-client-node-customer/pkgs/container/abc-mpc-client-node-customer

GitHub Packages에서 pull (권장)

# 최신 버전 pull (인증 불필요)
docker pull ghcr.io/ahnlabio/abc-mpc-client-node-customer:latest

# 특정 버전 pull
docker pull ghcr.io/ahnlabio/abc-mpc-client-node-customer:0.1.3

# 편의를 위해 짧은 태그 지정 (선택)
docker tag ghcr.io/ahnlabio/abc-mpc-client-node-customer:0.1.3 abc-mpc-client-node-customer:latest

제공되는 태그

태그설명
latest최신 릴리스
<version>특정 버전 (예: 0.1.3)
<version>-<git-sha>특정 커밋 기반 (예: 0.1.3-abc1234)

tar 파일 로드 (임시/오프라인)

GitHub 접근이 불가한 폐쇄망 환경 등에서는 ABC가 직접 tar 파일로 전달해드립니다.

docker load -i abc-mpc-client-node-customer.tar

최신 버전

구분이미지 태그
Client Node (Customer)ghcr.io/ahnlabio/abc-mpc-client-node-customer:0.1.3

실행

docker run -d \
--name abc-mpc-client-node \
--restart=unless-stopped \
-p 9091:9091 \
-e WAAS_API_URL="https://api.waas.myabcwallet.com" \
ghcr.io/ahnlabio/abc-mpc-client-node-customer:latest

환경변수

ABC가 제공하는 URL을 환경변수로 설정합니다.

변수설명
APP_PORT서비스 포트 (기본 9091)
WAAS_API_URLhttps://api.waas.myabcwallet.com (MPC Node 통신, 사용자/키 조회, 토큰 발급, 주소 변환)

WAAS_API_URL은 필수입니다. ABC가 제공하는 URL을 반드시 설정하세요. 미설정 시 서비스가 정상 동작하지 않습니다.


동작 확인

헬스 체크

curl http://localhost:9091/

응답 예시

{
"name": "abc-mpc-client-node-customer",
"version": "0.1.0_1_abc1234",
"build_type": "customer",
"time": "2026-04-13T06:50:00.000000000+00:00"
}

API 문서 (Swagger UI)

브라우저에서 http://localhost:9091/api/docs 접속 시 전체 API 문서와 테스트 UI를 확인할 수 있습니다.


인증

Client Node의 모든 보호된 API는 Authorization: Bearer <access_token> 헤더를 필요로 합니다.

고객사 서버 → WaaS v3 인증 API → Access Token 발급

Client Node API 호출 (Bearer: access_token)

Client Node → MPC Node / WaaS API

만료/잘못된 토큰의 경우 HTTP 401 Unauthorized와 함께 {"error":"Authentication failed: ..."} 형태로 에러 메시지가 반환됩니다. 고객사는 이 응답을 보고 토큰 재발급 후 재시도하면 됩니다.

Access Token 발급에 관한 자세한 내용은 WaaS v3 인증 API 문서를 참고하세요.


API 개요

기능메서드경로
헬스 체크GET/
키쉐어 생성POST/v3/wallet/generate
키쉐어 복구POST/v3/wallet/recover
서명POST/v3/wallet/sign
공개키 조회POST/v3/wallet/publickey
비밀번호 검증POST/v3/wallet/validate/password
키쉐어 검증POST/v3/wallet/validate/share
등록된 키 조회GET/v3/wallet/key
MPC 토큰 발급GET/v3/wallet/token
사용자 정보 조회GET/v3/wallet/user
지갑 정보 조회GET/v3/wallet

키쉐어 생성

MPC 키쉐어를 생성합니다. 지원 curve는 secp256k1ed25519입니다.

생성 완료 시 다음 필드가 반환됩니다.

필드설명
key_id키 식별자 (64자리 hex). 서명 요청 시 사용
encrypted_share암호화된 키쉐어. 서명의 핵심 데이터
secret_store키쉐어 복호화에 필요한 시크릿 데이터
public_key압축된 공개키 (hex, 0x 접두사 포함)
curve사용된 curve

보안 권장사항: 반환된 값들은 고객사 서버에서 반드시 암호화하여 보관해야 합니다. 유출 시 보안 위험이 발생할 수 있으므로 저장 및 접근 권한 관리에 각별히 주의하세요.

요청 예시

curl -X POST http://localhost:9091/v3/wallet/generate \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"curve": "secp256k1",
"password": "user_password"
}'

응답 예시

{
"key_id": "0f43f4e5fc30e66c2846d528dbaab885b09b914cbfd338c47d366d78f1f383af",
"encrypted_share": "GQmxNOxIYYdzSYXinfBC1LFo...",
"secret_store": "3Nt0bVPz70zjopUyDEZUPEviUgD+122mzC6HbIuoC+Ce1NbUZfHSxKdcEnXRxKf0X8KgiY2RGocS24d9W+DavQ==",
"curve": "secp256k1",
"public_key": "0x031714762cfcca743ace9b52bc2e3971ae131cae72610d85d90ebf4b4c417dbd72"
}

같은 curve의 키가 이미 존재하는 경우 409 Conflict를 반환합니다.


키쉐어 복구

기기 변경이나 데이터 유실 등으로 저장된 키쉐어를 잃어버린 경우, 서버에 등록된 키 정보를 기반으로 키쉐어를 복구할 수 있습니다.

복구 시 새로운 key_id 가 발급되지만 기존 키와 동일한 공개키를 사용하는 새로운 키쉐어가 생성됩니다. 블록체인 주소나 자산에는 영향이 없습니다.

요청 예시

curl -X POST http://localhost:9091/v3/wallet/recover \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"curve": "secp256k1",
"password": "user_password"
}'

응답 예시

{
"key_id": "f846acc0dc22ced1d66adfc15782fdbad1807a307d7d01aa7b4633185fd4bb5b",
"encrypted_share": "+6y0q83McPzjnWq7vMfx3340W+uWwEGVmutk...",
"secret_store": "iShfqMwgMEO/Z1JLqk4kzWVrVAn/k3jNjM0uhCq48CM+/RdL2LGfiMPYBxXu/z02m7wAxa7RoYJ5+/6GmO1neg==",
"curve": "secp256k1",
"public_key": "0x031714762cfcca743ace9b52bc2e3971ae131cae72610d85d90ebf4b4c417dbd72"
}

서명

Client Node는 curve에 따라 적합한 서명 방식을 자동으로 선택합니다. 외부 API에서는 /v3/wallet/sign 단일 엔드포인트로 호출하며, 내부적으로 다음과 같이 처리됩니다.

Curve내부 서명 방식설명
secp256k1MTA 서명Multiplicative-to-Additive 프로토콜 기반 보안 강화 서명
ed25519기본 서명표준 EdDSA 서명

서명 결과로 반환되는 signature는 hex 인코딩된 문자열입니다.

  • secp256k1 (MTA): r(32bytes) + s(32bytes) + v(1byte) = 65바이트, 130자 hex
  • ed25519: 64바이트, 128자 hex

요청 예시

curl -X POST http://localhost:9091/v3/wallet/sign \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"key_id": "0f43f4e5fc30e66c2846d528dbaab885b09b914cbfd338c47d366d78f1f383af",
"encrypted_share": "GQmxNOxIYYdzSYXinfBC1LFo...",
"secret_store": "3Nt0bVPz70zjopUyDEZUPEviUgD+122mzC6HbIuoC+Ce1NbUZfHSxKdcEnXRxKf0X8KgiY2RGocS24d9W+DavQ==",
"curve": "secp256k1",
"message": "2caedcc9efe11bfb2aaaa1474a9d1c803bce969c692fe890ebb2c8fd4db00bae"
}'

message는 서명할 데이터의 해시값(hex 문자열, 0x 접두사 없이)입니다.

응답 예시

{
"signature": "50247596f121b126ffa7a0439aba0e70a68abead61b680700ec8c23ebd7b7a8c3157f6b60cc6acde5681f8c64692b988db03940c324823411005d0ff690f13701b"
}

동시 서명 제한: MTA 서명은 Multi-round 프로토콜을 사용하므로, 동일한 키에 대해 동시에 여러 서명 요청을 보내지 않도록 주의하세요. key_id 단위로 큐 또는 락을 걸어 순차 처리하는 것을 권장합니다.


공개키 조회

키쉐어로부터 공개키를 계산하여 반환합니다. 블록체인 주소 생성에 사용됩니다.

curl -X POST http://localhost:9091/v3/wallet/publickey \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"key_id": "0f43f4e5fc30e66c2846d528dbaab885b09b914cbfd338c47d366d78f1f383af",
"encrypted_share": "GQmxNOxIYYdzSYXinfBC1LFo...",
"secret_store": "3Nt0bVPz70zjopUyDEZUPEviUgD+122mzC6HbIuoC+Ce1NbUZfHSxKdcEnXRxKf0X8KgiY2RGocS24d9W+DavQ==",
"curve": "secp256k1",
"password": "user_password"
}'

응답 예시

{ "public_key": "0x031714762cfcca743ace9b52bc2e3971ae131cae72610d85d90ebf4b4c417dbd72" }

검증

서명에 사용할 키쉐어와 비밀번호가 유효한지 사전에 검증할 수 있습니다. 서명 전에 검증을 수행하면 잘못된 비밀번호나 손상된 키쉐어로 인한 서명 실패를 미리 방지할 수 있습니다.

비밀번호 검증

curl -X POST http://localhost:9091/v3/wallet/validate/password \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"password": "user_password",
"secret_store": "3Nt0bVPz70zjopUyDEZUPEviUgD+122mzC6HbIuoC+Ce1NbUZfHSxKdcEnXRxKf0X8KgiY2RGocS24d9W+DavQ=="
}'

키쉐어 검증

curl -X POST http://localhost:9091/v3/wallet/validate/share \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"encrypted_share": "GQmxNOxIYYdzSYXinfBC1LFo...",
"secret_store": "3Nt0bVPz70zjopUyDEZUPEviUgD+122mzC6HbIuoC+Ce1NbUZfHSxKdcEnXRxKf0X8KgiY2RGocS24d9W+DavQ=="
}'

두 API 모두 다음 응답 형태를 반환합니다.

{ "result": true }

지갑 정보 조회

지갑 정보 조회

사용자의 지갑 목록과 각 지갑의 블록체인 주소를 조회합니다.

curl http://localhost:9091/v3/wallet \
-H "Authorization: Bearer $ACCESS_TOKEN"

응답 예시

{
"user_id": "470021fdc945471396a9e16ab320c017",
"wallets": [
{
"key": {
"curve": "secp256k1",
"public_key": "0x031714762cfcca743ace9b52bc2e3971ae131cae72610d85d90ebf4b4c417dbd72"
},
"address": {
"evm": "0x6F8bbD9b3FABa14b3b1F70d3e6B6c11b5cD1FBde",
"btc": "bc1q8nn2d8z87uq0f0tll74q9cjucrychpt3959ly6",
"aptos": "0x7da291585cc019f3da0270d345c00fec781f796306714f5f400a714ad6df5453",
"tron": "TL91QhiMbY87kTYSnUhktuqA3V62JMxuK7",
"xrp": "raZriQmumrngJhBb271q2zUU8x11Mx2ax3"
}
},
{
"key": {
"curve": "ed25519",
"public_key": "0xb0786dda97a85a0bbd1c2fddfc3e01cad0946a1a2183fa06808645af35aefbb7"
},
"address": {
"solana": "CssGFVGgZH54VESheuf3TzzpHGmLmq63N87QL46DMcoY"
}
}
]
}

키 목록 조회

curl http://localhost:9091/v3/wallet/key \
-H "Authorization: Bearer $ACCESS_TOKEN"

사용자 정보 조회

curl http://localhost:9091/v3/wallet/user \
-H "Authorization: Bearer $ACCESS_TOKEN"

MPC 토큰 발급

특정 key_id에 대한 MPC Node 호출용 JWT 토큰을 발급합니다.

curl "http://localhost:9091/v3/wallet/token?id=<key_id>" \
-H "Authorization: Bearer $ACCESS_TOKEN"

에러 응답

에러 발생 시 다음과 같은 형태의 JSON이 반환됩니다.

{ "error": "에러 메시지" }
상태 코드설명예시 메시지
200성공-
400잘못된 요청 파라미터Invalid curve
401인증 실패 (토큰 누락/만료)Authentication failed: {"code":"757","message":"JWT_EXPIRED"}
404리소스 없음-
409충돌 (예: 동일 curve의 키가 이미 존재)secp256k1 key already exists for this user
500서버 내부 에러Upstream returned 503 Service Unavailable: ...

토큰 만료 시 401 응답이 내려오므로 고객사 백엔드는 이 응답을 캐치하여 Access Token 재발급 후 재시도하는 로직을 구현해야 합니다.


docker-compose 예시

version: "3.8"

services:
abc-mpc-client-node:
image: ghcr.io/ahnlabio/abc-mpc-client-node-customer:latest
container_name: abc-mpc-client-node
restart: unless-stopped
ports:
- "9091:9091"
environment:
APP_PORT: "9091"
WAAS_API_URL: "https://api.waas.myabcwallet.com"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9091/"]
interval: 30s
timeout: 5s
retries: 3

실행:

docker-compose up -d

Client Node는 Stateless 구조이므로 인스턴스를 수평 확장할 수 있습니다.


네트워크 구성 권장사항

내부 접근만 허용

Client Node는 고객사 백엔드에서만 접근 가능하도록 제한해야 합니다. 외부 인터넷에 직접 노출해서는 안 됩니다.


업그레이드

  1. 기존 컨테이너 중지
docker stop abc-mpc-client-node
docker rm abc-mpc-client-node
  1. 새 이미지 pull (권장) 또는 tar 로드
# GitHub Packages에서 pull
docker pull ghcr.io/ahnlabio/abc-mpc-client-node-customer:<new-version>

# 또는 tar 파일로 받은 경우
docker load -i abc-mpc-client-node-customer-<new-version>.tar
  1. 새 컨테이너 실행 (동일한 환경변수로)
docker run -d \
--name abc-mpc-client-node \
--restart=unless-stopped \
-p 9091:9091 \
-e APP_PORT="9091" \
-e WAAS_API_URL="https://api.waas.myabcwallet.com" \
ghcr.io/ahnlabio/abc-mpc-client-node-customer:<new-version>
  1. 헬스 체크로 동작 확인
curl http://localhost:9091/

모니터링

헬스 체크

정기적으로 GET /를 호출하여 서비스 상태를 확인합니다.

# 30초마다 헬스 체크
while true; do
status=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:9091/)
echo "$(date): status=$status"
sleep 30
done

로그 확인

docker logs -f abc-mpc-client-node

주요 로그 패턴

로그의미
INFO request: finished processing request latency=XXX ms status=200정상 요청 처리
ERROR status:401 Unauthorized, error: Authentication failed: ...토큰 만료/잘못됨
ERROR status:500 Internal Server Error, error: Upstream returned ...WaaS API / MPC Node 통신 에러

트러블슈팅

502/504 에러

MPC Node 또는 WaaS API와의 네트워크 연결 문제일 가능성이 높습니다.

  1. WAAS_API_URL 환경변수 확인
  2. Client Node 컨테이너에서 해당 URL에 접근 가능한지 확인
docker exec abc-mpc-client-node sh -c "curl -s -o /dev/null -w '%{http_code}' $WAAS_API_URL/"

401 Unauthorized

Access Token이 만료되었거나 잘못된 경우입니다.

{"error":"Authentication failed: {\"code\":\"757\",\"message\":\"JWT_EXPIRED\"}"}

고객사 백엔드에서 Access Token을 재발급 후 재시도합니다.

409 Conflict (키 생성 시)

동일 curve의 키가 이미 존재하는 사용자입니다. 이 경우 키쉐어 복구(POST /v3/wallet/recover)를 사용해야 합니다.

MTA 서명 실패 / 타임아웃

동일 키에 대한 동시 서명이 원인일 수 있습니다. 고객사 백엔드에서 key_id 단위로 순차 처리하도록 큐 또는 락을 적용하세요.


운영 시 주의사항

  • Client Node는 WaaS Gateway를 통해 MPC Node와 통신하므로, 네트워크 지연이 낮은 환경에 배치하는 것을 권장합니다. MPC 서명은 다중 라운드 프로토콜로 동작하기 때문에 네트워크 지연이 서명 소요 시간에 직접적인 영향을 줍니다.
  • Client Node의 포트(기본 9091)는 고객사 백엔드에서만 접근 가능하도록 네트워크 접근 제어를 설정하는 것을 권장합니다. 외부에서 직접 접근 가능하게 해서는 안 됩니다.
  • 키 생성/복구 시 반환되는 key_id, encrypted_share, secret_store 정보는 서명에 필수적인 중요 데이터입니다. 고객사 서버에서 반드시 암호화하여 보관해야 하며 유출되지 않도록 주의하세요.
  • 동일한 키에 대해 동시에 여러 서명 요청을 보내지 않아야 합니다. MTA 서명은 Multi-round 프로토콜을 사용하기 때문입니다.

보안 참고사항

  • 개인키 미노출: MPC 프로토콜의 어떤 단계에서도 완전한 개인키가 단일 장소에 존재하지 않습니다.
  • 독립 운영 노드: MPC Node 1(ABC)과 Node 2(제3자 기관)가 독립적으로 운영되어, 단일 기관 침해로는 키가 노출되지 않습니다.
  • 클라이언트 측 암호화: 키쉐어는 사용자 비밀번호로 암호화되어 반환됩니다. Client Node는 암호화된 데이터만 처리합니다.
  • Stateless: Client Node는 자체적으로 키 데이터를 저장하지 않으므로 트래픽 증가 시 인스턴스를 수평 확장할 수 있습니다.

지원

배포 중 문제가 발생하면 ABC 지원팀으로 문의하세요. 이슈 리포트 시 다음 정보를 함께 전달해주시면 빠른 처리가 가능합니다.

  • 이미지 버전 (curl http://localhost:9091/version 필드)
  • 컨테이너 로그 (docker logs abc-mpc-client-node --tail 200)
  • 발생한 요청의 API 경로와 상태 코드
  • 재현 절차