안녕하세요?

그 동안 Hyperledger Fabric을 이용하여 개발모드와 운영모드에서 체인코드를 적용하여 REST API를 통해 트랜잭션을 일으켜 테스트를 해봤습니다.
현재까지의 환경에서는 REST API를 포함하여 http 기반으로 요청을 주고 받았습니다.
(아직 다수의 Peer로 블록체인 네트워크를 구성하진 않았지만 이 번 글에서 설명할 TLS가 활성화되어 있지 않으면 peer 간의 통신도 http 기반의 grpc로 이루어 집니다.)
이 번 글에서는 REST API 및 Peer간 통신에 TLS를 적용하는 방법에 대해서 설명드리겠습니다.

1. 멤버쉽 서비스를 위한 Self-Signed Certificate 생성

TLS가 활성화되어 있으면 아래 그림과 같이 블록체인 네트워크 상에 각 Peer는 멤버쉽 서비스에 스스로를 등록할 때 TLS Handshake 과정을 거치면서 인증서 기반으로 인증을 받게 됩니다.
당연히 인증서가 유효하지 않으면 Peer가 멤버쉽 서비스에 접속하지 못합니다.
마친가지로 Peer간 통신에서도 TLS 인증을 통해서 통신을 하게됩니다.
그래서 TLS 기반의 통신을 위해서는 각 통신 구간 즉, 멤버쉽 서비스 < –> Peer 와 Peer < –> Peer 구간을 위한 인증서를 등록해야 합니다.
먼저, 멤버쉽 서비스 < –> Peer 통신에서 사용하기 위한 인증서를 만들어보겠습니다.

적당한 위치에 디렉토리를 하나 만듭니다. 전 tls라는 디렉토리를 만들었습니다.

$ mkdir tls
$ cd tls

다음의 절차대로 필요한 인증서를 생성하시기 바랍니다. 먼저 Certificate Authority(CA) 를 생성합니다.

$ openssl genrsa -aes256 -out ca-key.pem 4096

아래에서는 “Common Name”을 유의해서 입력하여야 합니다. 접속해야할 서버의 IP 또는 호스트네임이 되어야 합니다.
나중에 멤버쉽 서비스 컨테이너의 호스트네임을 “membersrvc” 로 실행할 것이기 때문에 Common Name을 “membersrvc”로 입렵합니다.

$ openssl req -new -x509 -days 365 -key ca-key.pem -sha256 -out ca.pem
Enter pass phrase for ca-key.pem:
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:KR
State or Province Name (full name) [Some-State]:
Locality Name (eg, city) []:Seoul
Organization Name (eg, company) [Internet Widgits Pty Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:membersrvc
Email Address []:

Server 키와 certificate signing request (CSR) 을 만듭니다.

$ openssl genrsa -out server-key.pem 4096
$ openssl req -subj "/CN=membersrvc" -sha256 -new -key server-key.pem -out server.csr

다음으로 앞서 생성한 CA를 이용하여 public key를 만듭니다.
여기서 주의할 점은, TLS 접속시 접속을 허용할 DNS 또는 IP를 명시해야 합니다.

$ echo subjectAltName = DNS:membersrvc,DNS:vp0,DNS:vp1,IP:172.16.151.175,IP:172.16.151.162,IP:172.17.0.1,IP:172.17.0.2,IP:172.17.0.3,IP:172.17.0.4 > extfile.cnf
$ openssl x509 -req -days 3650 -sha256 -in server.csr -CA ca.pem -CAkey ca-key.pem \
   -CAcreateserial -out server-cert.pem -extfile extfile.cnf
Signature ok
subject=/CN=membersrvc
Getting CA Private Key
Enter pass phrase for ca-key.pem:

다음으로 클라이언트 인증을 위한 클라이언트 키와 certificate signing request(CSR)을 만듭니다.

$ openssl genrsa -out key.pem 4096
$ openssl req -subj '/CN=client' -new -key key.pem -out client.csr

클라이언트 인증을 위한 extentions config 파일을 생성합니다.

$ echo extendedKeyUsage = clientAuth > extfile.cnf

public key를 만듭니다.

$ openssl x509 -req -days 3650 -sha256 -in client.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out cert.pem -extfile extfile.cnf
Signature ok
subject=/CN=client
Getting CA Private Key
Enter pass phrase for ca-key.pem:

2. 생성된 인증서를 멤버쉽 서비스 및 Validating Peer에 설정

성공적으로 인증서가 생성되었으면 각 멤버쉽 서비스 및 Validating Peer에 인증서를 복사하고 설정을 합니다.
(컨테이너 실행이 되지 않았으면 실행을 하고 진행합니다)

$ cd ../
$ docker cp tls < 멤버쉽 서비스 컨테이너 ID>:/root/tls
$ docker cp tls :/root/tls

다음으로 멤버쉽 컨테이너에 접속해서 설정파일을 다음의 그림과 같이 설정합니다.

 멤버쉽 서비스에 접속
$ docker exec -it < 맴버쉽 서비스 컨테이너 ID> bash

컨테이너 접속 후
# cd membersrvc
# vi membersrvc.yaml

수정 후 다음 명령으로 캐시 및 이전 생성된 인증서 파일들을 삭제합니다.

# rm -rf /var/hyperledger/*

여기까지 완료되었으면 멤버쉽 서비스 컨테이너에서 빠져나옵니다.

다음으로 Validating Peer를 설정하겠습니다. 다음 명령어를 통해 Validating Peer로 접속해서 설정파일을 수정합니다.

Validating Peer에 접속
$ docker exec -it < Validating Peer 컨테이너 ID> bash

컨테이너 접속 후
# cd peer
# vi peer.yaml

멤버쉽 서비스와 마찬가지로 캐시 및 생성된 인증서 파일을 삭제하고 컨테이너에서 빠져나옵니다.

# rm -rf /var/hyperledger/*

멤버쉽 서비스와 Validating Peer 의 수정이 완료되었으면 docker commit을 통해 새로운 이미지로 태깅합니다.

$ docker commit < validating Peer 컨테이너 ID> hyperledger/peer:1.2
$ docker commit < 멤버쉽 서비스 컨테이너 ID> hyperledger/membersrvc:1.0

그리곤 컨테이너 재시작합니다.(docker-compose.yml 파일의 위치에서 명령을 해야하는 거 유념하시기 바랍니다.)

$ docker-compose down
$ docker-compose up

에러없이 컨테이너 실행되는지 확인합니다. 에러없이 실행이 되었으면 바로 다음 Peer < –> Peer 통신을 위한 설정으로 넘어갑니다.

3. Peer 간 p2p 통신을 위한 TLS 설정

앞 단계에서 실행된 컨테이너에서 peer 간 통신을 위한 인증서 설정작업을 이어서 진행하겠습니다.
정상적으로 멤버쉽 서비스가 실행이되었으면 “/var/hyperledger/production/.membersrvc” 디렉토리 밑에 멤버쉽 서비스가 생성한 각종 인증서들이 존재합니다.
그 중 peer간 통신을 위해서는 “tlsca.cert” , “tlsca.priv” 파일이 필요합니다. 이 파일들을 Validating Peer로 복사하면 됩니다.

$ docker cp < 멤버쉽 서비스 컨테이너 ID>:/var/hyperledger/production/.membersrvc/tlsca.cert tlsca.cert
$ docker cp < 멤버쉽 서비스 컨테이너 ID>:/var/hyperledger/production/.membersrvc/tlsca.priv tlsca.priv
$ docker cp tlsca.cert :/root/tls/tlsca.cert
$ docker cp tlsca.priv :/root/tls/tlsca.priv

복사한 후 Validating Peer의 컨테이너에 접속하여서 설정파일 수정을 합니다.

Validating Peer에 접속
$ docker exec -it < Validating Peer 컨테이너 ID> bash

컨테이너 접속 후
# cd peer
# vi peer.yaml

설정을 저장하고 앞서 한 것과 같이 캐시를 삭제하고 컨테이너에서 빠져나옵니다.

# rm -rf /var/hyperledger/*

docker commit을 통해 새로운 이미지로 태깅합니다.

$ docker commit < Validating Peer 컨테이너 ID > hyperledger/peer:1.3

여기까지 완료하였으면 다음의 docker-compose 파일을 통해 컨테이너를 실행합니다.
아래의 docker-compose 파일은 하나의 멤버쉽 서비스와 2개의 peer로 구성되어 있습니다. 참조하셔서 테스트하는 환경에 맞춰 수정해서 사용하시기 바랍니다.
런타임 환경 구성이 완료되고 REST API를 통한 테스트는 http 대신 https를 통해 호출하시기 바랍니다.
그리고, REST client 툴은 https 호출을 위해서는 클라이언트에 SSL 인증서를 설정하거나, SSL 인증서 validation 기능을 disable 해서 테스트하시기 바랍니다.
https://github.com/mjkong/blockchain_hyperledger/blob/master/docs/Setup/prodmode/2_peers/docker-compose.yml

membersrvc:
  image: hyperledger/membersrvc:1.0
  ports:
    - "7054:7054"
  hostname: membersrvc
  container_name: membersrvc
  command: membersrvc
vp0:
  image: hyperledger/peer:1.3
  ports:
    - "7050:7050"
    - "7051:7051"
    - "7053:7053"
  environment:
    - CORE_PEER_ADDRESSAUTODETECT=true
    - CORE_VM_ENDPOINT=https://192.168.99.100:2476
    - CORE_LOGGING_LEVEL=DEBUG
    - CORE_PEER_ID=vp0
    - CORE_PEER_PKI_ECA_PADDR=membersrvc:7054
    - CORE_PEER_PKI_TCA_PADDR=membersrvc:7054
    - CORE_PEER_PKI_TLSCA_PADDR=membersrvc:7054
    - CORE_SECURITY_ENABLED=true
    - CORE_SECURITY_ENROLLID=test_vp0
    - CORE_SECURITY_ENROLLSECRET=MwYpmSRjupbT
  hostname: vp0
  container_name: vp0
  links:
    - membersrvc
  command: sh -c "sleep 5; peer node start"
vp1:
  image: hyperledger/peer:1.3
  ports:
    - "7061:7061"
  environment:
    - CORE_PEER_ADDRESSAUTODETECT=true
    - CORE_VM_ENDPOINT=https://192.168.99.100:2476
    - CORE_LOGGING_LEVEL=DEBUG
    - CORE_PEER_ID=vp1
    - CORE_PEER_ADDRESS=0.0.0.0:7061
    - CORE_PEER_LISTENADDRESS=0.0.0.0:7061
    - CORE_PEER_PKI_ECA_PADDR=membersrvc:7054
    - CORE_PEER_PKI_TCA_PADDR=membersrvc:7054
    - CORE_PEER_PKI_TLSCA_PADDR=membersrvc:7054
    - CORE_SECURITY_ENABLED=true
    - CORE_SECURITY_ENROLLID=test_vp2
    - CORE_SECURITY_ENROLLSECRET=vQelbRvja7cJ
    - CORE_PEER_DISCOVERY_ROOTNODE=192.168.99.100:7051
  hostname: vp1
  container_name: vp1
  links:
    - membersrvc
    - vp0
  command: sh -c "sleep 5; peer node start"

4. 정리하며

여기까지 블록체인 네트워크의 TLS 설정에 대해서 설명하였습니다.
지금까지의 내용으론 기본적인 블록체인 런타임 환경을 구성하고 체인코드를 디플로이해서 REAT API를 통해 테스트하는 과정을 개발모드와 운영모드, 그리고 TLS 적용된 환경에서 진행할수 있도록 설명하였습니다.
앞으로는 4개 이상의 Peer들로 구성하여 합의 알고리즘을 적용하는 방법고 SDK를 활용하여 클라이언트 어플리케이션을 개발하는 환경 구성에 대해서 설명할 예정입니다.
많은 기대 바랍니다.