hashicorp consul (2018. draft)

consul 테스팅 자료 정리.  

vault 의 storage backend 용도로 consul을 사용하는 것에 집중을 하므로 Service Discovery, Health Checking 에 대한 테스팅은 생략을 하였습니다.


https://www.consul.io/intro/index.html

What is Consul?

Service Discovery

Health Checking

KV Store

Multi Datacenter

Getting Started

Install Consul


Run the Agent : server or client mode


Services


Consul Cluster

consul agent -server 를 처음 실행하는 경우 -bootstrap-expect=1 을 지정해 주어야 한다. 

현재 존재하는 cluster에 조인하기 위해서 단일한 멤버 하나만 알면 된다. 이 멤버 하나는 server mode에서 돌아가지 않아도 조인할 수 있다.  consul cluste에 속해있는 아무 agent 주소를 이용하면 된다.

$ consul join 172.20.20.11
$ consul members

AWS 등 클라우드에서는 노드 추가시 자동으로 consul 클러스터에 join 하도록 설정을 할 수 있다. AWS의 경우에는  다음과 같이 설정을 한다. tag_key, tag_value 를 설정해야 한다.

이경우 ec2:Describe* 에 대해서 읽을 수 있는 권한이 있어야 한다. https://github.com/hashicorp/terraform-aws-consul/blob/master/modules/consul-iam-policies/main.tf 참고.

$ consul agent -retry-join "provider=aws tag_key=... tag_value=..."


Health Checks


KV Data

$ consul kv put redis/config/minconns 1
$ consul kv get redis/config/minconn
$ consul kv get -detailed redis/config/minconns
$ consul kv get -recurse
$ consul kv delete redis/config/minconns


Web UI

ui를 활성화를 한 경우 기본으로는 localhost에서만 접속 가능하다.

http://localhost:8500/ui

proxy server를 세팅하거나 docker 등을 이용하여 consul UI를 이용할 수 있고 ssh 포트 포워딩으로 간단하게 ui에 접속할 수도 있다.

아래와 같이 ssh 세팅을 한 후  localhost의 8500 port를 이용하여 consul UI에 접근할 수 있다. (http://localhost:8500/)

$ ssh -p7722 -i ~/private/xxxxxx -L 8500:localhost:8500  taejoon.moon@staging4.yogiyo.co.kr

consul 설정에서 ui 를 활성화하면서 접근할 ip, ports 등을 지정하여 직접 consul ui로 접속하도록 설정을 할 수도 있다.


Next Steps

Documentation

Internals 

Architecture 등 상세자료임.

Architecture https://www.consul.io/docs/internals/architecture.html : 각종 용어 정리.

Consensus Protocol https://www.consul.io/docs/internals/consensus.html : Failure Tolerance 에 대한 정보가 있음. 서버 3대가 있으면 1대가 죽어도 서비스에 문제가 없음.

Commands

Agent

Running and Stopping

https://www.consul.io/docs/agent/basics.html

The Consul agent is the core process of Consul. The agent maintains membership information, registers services, runs checks, responds to queries, and more. The agent must run on every node that is part of a Consul cluster.

agent 는 멤버쉽 정보 관리, 서비스 등록, cheks 실행, 쿼리에 대한 응답 등의 역할을 한다. Consul cluster 에 속한 모든 노드에서 실행을 해야 한다. 

Any agent may run in one of two modes: client or server. 

agent는 client 또는 server 모드로 실행을 한다.

DNS Interface


Configuration 

https://www.consul.io/docs/agent/options.html 상세 설정

주요옵션

server

bootstrap-expect

data-dir

bind

config-dir


Service Definitions


Check Definitions


Encryption

https://www.consul.io/docs/agent/encryption.html

gossip trrafic 을 암호화하는 것과 RPC를 암호화하는 두가지가 있다.

gossip encryption 은 consul agent에 encryption key만 설정을 하면 된다. (consul keygen 이용하여 생성 가능함) consul 클러스터에서 모든 노드가 클러스터 정보를 주고 받기 위해서 동일한 encryption key를 가져아 한다.


TLS를 이용한 RPC 암호화는 서버와 클라이언트간의 신원을 확인한다. 이 옵션을 활성화하기 위해서는 모든 클라이언트와 서버고 single CA로 생성한 key paris가 필요하다. private CA를 이용할 수 있다 

TLS 관련된 옵션으로는 verify_outgoing, verify_server_hostname, verify_incoming 이 있다.

verify_outgoing : agent 에서 밖으로 나가는 커넥션을 확인한다. server node에서는 ca_file(ca_path) 옵션으로 CA 설정을 하고 cert_file 과 key_file 옵션으로 key pari를 설정해야 한다.

verify_server_hostname : 밖으로 나가는 연결에서 hostname 확인을 한다. 모든 서버는 server.<datacenter>.<domain> 형태의 인증서를 가져야 하며 그러지 않을 경우 client 와의 handshake가 거절될 것이다. 

verify_incoming : 서버에서 들어오는 연결의 신뢰성을 확인한다. 모든 클라이언트는 cert_file 과 key_file 옵션으로 key pari를 설정해야 한다. 서버에서는 TLS 연결이 아닌 경우에는 허용을 하지 않는다. 클라이언트에서 TLS를 쓰도록 강제하려면 verify_outgoing 옵션도 설정을 해야 한다. 


TLS 를 설정할 때 verify_server_hostname 는 필수는 아니다. 이 설정을 하면 특정 클라이언트를 서버로 재시작하여 악용하는 경우를 막을 수 있다. https://www.consul.io/docs/agent/options.html#verify_server_hostname


문서에는 클라이언트 인증서를 만들 때 openssl에서  클라이언트와 서버 인증을 활성화히 위한 Extended Key Usage 가 있어야 한다고 나와있다.

Note: Client certificates must have Extended Key Usage enabled for client and server authentication.

http://russellsimpkins.blogspot.kr/2015/10/consul-adding-tls-using-self-signed.html 문서에서 이에 대한 확인 내용이 나온다. 그렇지만  Ubuntu 16.04 에서 자체 CA 사인한 인증서를 만들어서 인증서를 확인할 때 "X509v3 Extended Key Usage" 가 보이지는 않지만 TLS 동작은 잘 되었다. 

Ubuntu 16.04 에 기본 들어있는 /etc/ssl/openssl.cnf 에서는 extendedKeyUsage 라인이 주석처리 되어 있다. 이부분의 주석을 없애고 인증서 생성. 

# egrep extendedKey /etc/ssl/openssl.cnf
extendedKeyUsage = serverAuth,clientAuth
# openssl req -x509 -nodes -days 36500 -newkey rsa:2048 -keyout /etc/consul.d/ssl/consul-selfsigned.key -out /etc/consul.d/ssl/consul-selfsigned.crt \
-subj "/C=KR/ST=Seoul/L=Gangnam/O=xxx/OU=devops/CN=consul.example.co.kr
# openssl x509 -noout -text -in /etc/consul.d/ssl/consul-selfsigned.crt  | egrep -i exten -A5


client/server 모두 ca_file, cert_file, key_file, verify_outgoing 는 동일하게 설정을 하고 서버만 verify_incoming 옵션을 추가해주었다.  이 예제의 경우에는 server/cleint 의 key pair를 따로 만들지 않았다. 보안을 엄격히 적용하려면 둘다 따로 따로 만들어서 자체 CA로 사인은 해야 할 것이지만 TLS 기능 자체만 활성화하는데는 동일하게 사용을 해서 쓸 수 있다.

server

# egrep "ca_file|cert_file|key_file|verify" /etc/consul.d/config.json
  "ca_file": "/etc/consul.d/ssl/consul-selfsigned.crt",
  "cert_file": "/etc/consul.d/ssl/consul-selfsigned.crt",
  "key_file": "/etc/consul.d/ssl/consul-selfsigned.key",
  "verify_incoming": true,
  "verify_outgoing": true

client

# egrep "ca_file|cert_file|key_file|verify" /etc/consul.d/config.json
  "ca_file": "/etc/consul.d/ssl/consul-selfsigned.crt",
  "cert_file": "/etc/consul.d/ssl/consul-selfsigned.crt",
  "key_file": "/etc/consul.d/ssl/consul-selfsigned.key",
  "verify_outgoing": true


https://www.mauras.ch/securing-consul.html#tls 참고.



Telemetry

https://www.consul.io/docs/agent/telemetry.html : runtime metrics 설명. 주요 metric 설정 필요함.

Watches


Guides

확인이 필요한 문서들.

ACLs - This guide covers Consul's Access Control List (ACL) capability, which can be used to control access to Consul resources.

special tokens

  • acl_agent_master_token : cluster 에 join 을 할 때 필요함. 모든 consul server, client 에서 설정이 필요하다. 
  • acl_agent_token : https://www.consul.io/docs/guides/acl.html#acl-agent-token Catalog API를 통해서 노드의 metadata 등을 업데이트하는데 필요함. 
    • acl_agent_token 설정을 해주지 않으면 다음과 같은 ACLs 에러가 나온다.모든  consul server, client 에서 설정이 필요하다. 
2017/07/08 23:38:24 [WARN] agent: Node info update blocked by ACLs
2017/07/08 23:38:44 [WARN] agent: Coordinate update blocked by ACLs
  • acl_master_token : consul server 에서 필요함. server에서 bootstrap을 할 때 필요함. root 라고 생각을 하면 됨.
  • acl_token : token이 없을 때 사용하는 기본 토큰. anonymous policy를 이용할 수 도 있지만  anonymous policy 보다 acl_token을 이용하면 더 각 agent 별로 설정을 다르게 하는 등 좀 더 상세한 설정이 가능하다. 


rule 을 만들때 HCL과 json 포맷 두가지를 지원한다. 사람이 보기에는 HCL이 더 편하며 API를 이용하여 rule과 token을 만들 때에는 텍스트 파일을 변환하여 사용하는 것이 편리하다.

HCL format으로 acl 만들기. " 문자에 대해서 \ {escape) 를 설정해야 해서 불편하다.

$ curl \
    --request PUT \
    --data \
'{
  "Name": "my-app-token",
  "Type": "client",
  "Rules": "key \"\" { policy = \"read\" } key \"foo/\" { policy = \"write\" } key \"foo/private/\" { policy = \"deny\" } operator = \"read\""
}' http://127.0.0.1:8500/v1/acl/create?token=<management token>

스크립트 이용하기 : rule을 HCL format으로 example-key-acl.hcl 파일에 저장을 하면 이 hcl을 파일을 읽어들임. acl name을 example-key-acl 로 지정하여 스크립트 실행하면 agent token을 반환한다. 

# cat example-key-acl.hcl
# These control access to the key/value store.
key "" {
  policy = "read"
}
key "foo/" {
  policy = "write"
}
key "foo/private/" {
  policy = "deny"
}

# This controls access to cluster-wide Consul operator information.
operator = "read"


$ ./hcl_to_acl.sh example-key-acl.hcl example-key-acl
{"ID":"cc231037-0422-d5b5-7504-f74e97930899"}


 스크립트. acl_master_token 으로 스크립트를 실행하며 이 항목은 /etc/consul.d/*.json 파일에 있다고 가정을 한다.

# cat hcl_to_acl.sh
#!/bin/bash
# temp file
temp_file_01=.temp_file_01
temp_file_02=.temp_file_02

# args
hcl_file=$1
acl_name=$2

test -z $hcl_file && echo "hcl file is not exist " && exit 1
test -z $acl_name && echo "acl name is not exist " && exit 1

# convert hcl format for adding acl
#rules=`cat $hcl_file | egrep -v ^# | sed 's/\"/\\"/g' | tr '\n' ' '`
cat $hcl_file | egrep -v ^# | sed 's/\"/\\"/g' | tr '\n' ' ' > ${temp_file_01}

cat <<EOF > ${temp_file_02}
{
  "Name": "${acl_name}",
  "Type": "client",
  "Rules": "`cat ${temp_file_01}`"
}
EOF

master_token=`egrep "^\s+\"acl_master_token" /etc/consul.d/*.json | awk '{ print $3 }' | awk -F\" '{ print $2 }'`

# create acl
curl \
    --request PUT \
    --header "X-Consul-Token: ${master_token}" \
    --data @${temp_file_02} \
http://127.0.0.1:8500/v1/acl/create

# delete temp file
test -f ${temp_file_01} && rm -f ${temp_file_01}
test -f ${temp_file_02} && rm -f ${temp_file_02}


작업을 해보니 bash보다는 python-consul 을 이용하는 것이 훨씬 더 편리합니다.

https://python-consul.readthedocs.io/en/latest/


anonymous policy가 설정되어 있지 않을 때는 DNS lookup을 했을 때 조회가 안될 것이다.

$ dig @127.0.0.1 -p 8600 consul.service.consul +short

이제 anonymous policy를 설정하고 다시 조회를 해본다.  anonymous policy는 기본으로 들어있는 acl이기때문에 v1/acl/update api를 이용한다.

$ cat set_anonymous_acl.sh
#!/bin/bash
master_token=`egrep "^\s+\"acl_master_token" /etc/consul.d/*.json | awk '{ print $3 }' | awk -F\" '{ print $2 }'`

# create acl
curl \
    --request PUT \
    --header "X-Consul-Token: ${master_token}" \
    --data \
'{
  "ID": "anonymous",
  "Type": "client",
  "Rules": "node \"\" { policy = \"read\" } service \"consul\" { policy = \"read\" }"
}' http://127.0.0.1:8500/v1/acl/update

$ dig @127.0.0.1 -p 8600 consul.service.consul +short
192.168.40.16


Adding/Removing Servers - This guide covers how to safely add and remove Consul servers from the cluster. This should be done carefully to avoid availability outages.

Bootstrapping - This guide covers bootstrapping a new datacenter. This covers safely adding the initial Consul servers.

Bootstrapping is the process of joining these initial server nodes into a cluster. -> bootstrap은 처음 server를 실행할 때 이 서버노드를 클러스터에 추가하는 것이다. 이때는 아직 cluster leader 가 없는 단계이므로 bootstrap 옵션을 지정하여 이 서버가 leader로 설정이 될 수 있도록 하는 것이다


The recommended way to bootstrap is to use the -bootstrap-expect configuration option. This option informs Consul of the expected number of server nodes and automatically bootstraps when that many servers are available. To prevent inconsistencies and split-brain situations (that is, clusters where multiple servers consider themselves leader), all servers should either specify the same value for -bootstrap-expect or specify no value at all. Only servers that specify a value will attempt to bootstrap the cluster.


bootstrap-expect를 모든 servers에 동일하게 지정을 하거나 값을 지정하지 않으면 된다고 나온다. 그런데 처음 클러스터를 구성할 때 첫 서버노드는 bootstrap-expect가 있어야 클러스터를 구성할 수 있다.

bootstrap-expect=3 이라고 지정을 하면 3대의 server node 가 모두 join을 했을 때 leader를 선택한다.

bootstrap-expect=1 이라고 설정을 하고 server node를 두대를 띄우는 경우 다음과 같이 오직 한대의 노드만 bootstrap mode이어야 한다고 나온다.

[ERR] consul: 'ubuntu02' and 'consul02' are both in bootstrap mode. Only one node should be in bootstrap mode, not adding Raft peer.


consul info 에서  raft.last_log_index 정보에 최신 log index를 볼 수 있다. When running consul info on the followers, you should see raft.last_log_index converge to the same value once the leader begins replication. That value represents the last log entry that has been stored on disk. leader 가 replication을 할 때 동일한 수치를 보여야 한다? 이 값은 디스크에 저장된 최근 log 엔트리 값이다.

# salt -G 'roles:consul'  cmd.run 'consul info | grep last_log'
ubuntu01.example.com:
    	last_log_index = 1387
    	last_log_term = 23
consul02.example.com:
    	last_log_index = 1387
    	last_log_term = 23
ubuntu02.example.com:
    	last_log_index = 1387
    	last_log_term = 23


Outage Recovery - This guide covers recovering a cluster that has become unavailable due to server failures.


Server Performance - This guide covers minimum requirements for Consul servers as well as guidelines for running Consul servers in production.

최소 사양으로는 AWS t2.micro 3대의 서버 클러스터를 이야기하고 있음.

production server 요구사항은 나중에 필요할 때 찾아보면 될 것임

메모리 요구사항은 consul.runtime.alloc_bytes 의 값을 보고 판단을 할 수 있음.

확인해야 하는 것

client , server mode 이해하기. 

consul HA 구성하기.

노드 추가시 자동으로 클러스터 구성하기

백업하고 복구하기
UI : reverse proxy 로 구성을 할까? 아니면 원격에서 접속 가능하도록 한대만 설정을 할까? docker 로 구성할 수 있음.

기타 참고자료

보안설정하기 https://www.mauras.ch/securing-consul.html

https://github.com/brianshumate/ansible-consul