内容基于大量官网资料,请耐心阅读
系统及软件版本:consul-1.5.3+CentOS7
docker-compose搭建consul-1.5.3集群
只有一台服务器,我就用docker-compose搭建了
docker-compose.yml配置如下
version: '3.0'
services:
consul1:
image: consul:1.5.3
restart: always
container_name: consul_1
#-server:表示当前使用的server模式,-node:指定当前节点在集群中的名称,
#-config-dir:指定配置文件路径,定义服务的,缺省值为:/consul/config
#-data-dir: consul存储数据的目录;缺省值为:/consul/data
#-datacenter:数据中心名称,缺省值为dc1
#-ui:使用consul自带的web UI界面
#-bind: 绑定服务器的ip地址
#-client: 客户端可访问ip,缺省值为:“127.0.0.1”,即仅允许环回连接
#-bootstrap-expect:在一个datacenter中期望的server节点数目,consul启动时会一直等待直到达到这个数目的server才会引导整个集群.这个参数的值在同一个datacenter的所有server节点上必须保持一致
command: agent -server -client=0.0.0.0 -node=consul_1 -bootstrap-expect=3
volumes:
- /usr/local/docker_app/consul/consul_1/config:/consul/config
- /usr/local/docker_app/consul/consul_1/data/key:/consul/data/key
consul2:
image: consul:1.5.3
restart: always
container_name: consul_2
command: agent -server -client=0.0.0.0 -retry-join=consul_1 -node=consul_2
volumes:
- /usr/local/docker_app/consul/consul_2/config:/consul/config
- /usr/local/docker_app/consul/consul_2/data/key:/consul/data/key
consul3:
image: consul:1.5.3
restart: always
container_name: consul_3
command: agent -server -client=0.0.0.0 -retry-join=consul_1 -node=consul_3
volumes:
- /usr/local/docker_app/consul/consul_3/config:/consul/config
#证书路径
- /usr/local/docker_app/consul/consul_3/data/key:/consul/data/key
consul4:
image: consul:1.5.3
container_name: consul_4
restart: always
ports:
- 8500:8500
command: agent -client=0.0.0.0 -retry-join=consul_1 -ui -node=client
volumes:
- /usr/local/docker_app/consul/consul_4/config:/consul/config
- /usr/local/docker_app/consul/consul_4/data/key:/consul/data/key
docker-compse的语法就不介绍了,consul用的参数都写了注释,consul是C/S结构,配置三台server,一台client,数据卷配置了consul的配置文件,consul数据目录中的证书目录
如果出现下面报错
[root@coen ~] docker-compose up -d
Pulling consul1 (consul:1.5.3)...
ERROR: Get https://registry-1.docker.io/v2/: net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)`
编辑/etc/docker/daemon.json,添加
{
"registry-mirrors": ["https://registry.docker-cn.com","http://hub-mirror.c.163.com"]
}
安装完毕,运行docker exec -i consul_1 consul members,见到下面三台server,一台client就搭建起来了
Node Address Status Type Build Protocol DC Segment
consul_1 172.19.0.4:8301 alive server 1.5.3 2 dc1 <all>
consul_2 172.19.0.2:8301 alive server 1.5.3 2 dc1 <all>
consul_3 172.19.0.5:8301 alive server 1.5.3 2 dc1 <all>
client 172.19.0.3:8301 alive client 1.5.3 2 dc1 <default>
访问http://192.168.28.128:8500可以访问client的UI界面
看上面,“dcl”数据中心(consul能多数据中心,官方推荐一般3-5台性能佳)
“Services”服务列表(默认有consul)
“Ndes”节点列表
“Key / Value”分布式KV
“ACL”Consul用来控制访问API与数据
配置consul的TLS、ACl和Gossip Encryption
consul有三方面的安全保护机制
- Gossip Encryption:Consul使用Gossip协议来管理集群中的成员关系,以及把消息广播到集群中,通过UDP完成
- TLS:使用https加密consul的API、GRPC
- ACl:控制Services、Nodes、KV的读写权限
先配置最简单的Gossip Encryption
先生成Encryption
[root@coen docker_app] docker exec -t consul_1 consul keygen
RAo6b8QwxOTDd8Z0b4/Hiw==
“RAo6b8QwxOTDd8Z0b4/Hiw==”就是Encryption
在数据卷(/usr/local/docker_app/consul/consul_1/config/)下创建encrypt.json,写入Encryption
[root@coen docker_app] cd /usr/local/docker_app/consul/consul_1/config/
[root@coen config] echo '{"encrypt": "gf/aeGk4Ok7Lcpz7p6gCZg=="}' > encrypt.json
[root@coen config] cp encrypt.json ../../consul_2/config/
[root@coen config] cp encrypt.json ../../consul_3/config/
注意:每个server都得写入一样的值,值不一样server怎么交流?client作用是转发,不需要配置Gossip Encryption
配置consul的TLS
consul是基于CA验证的,可以选择官网那种一键生成,但是证书有效期有点短,我选择自己生成
需要安装openssl,这就不演示了,我在windows10上生成
#生成根证书key
openssl genrsa -out ca.key 2048
#生成根证书密钥
openssl req -new -x509 -days 7200 -key ca.key -subj "/CN=consul.com" -out ca.pem
#生成服务端私钥
openssl genrsa -out server.key 2048
#生成客户端私钥
openssl genrsa -out client.key 2048
#生成的服务端的CSR
#CSR 主要作用是 CA 会利用 CSR 文件进行签名使得攻击者无法伪装或篡改原有证书
openssl req -new -key server.key -subj "/CN=consul.com" -out server.csr
#生成的客户端的CSR
openssl req -new -key client.key -subj "/CN=consul.com" -out client.csr
#服务端自签名的证书
openssl x509 -req -sha256 -CA ca.pem -CAkey ca.key -CAcreateserial -days 3650 -in server.csr -out server.pem
#客户端自签名的证书
openssl x509 -req -sha256 -CA ca.pem -CAkey ca.key -CAcreateserial -days 3650 -in client.csr -out client.pem
可以看到CA有效期7200天!私钥和证书有效期3650天!可以设置小一点,定期更换,更安全;“CN”是只允许某个IP或者域名访问,我这设置成域名“consul.com”,灵活点
整理下
因为是docker搭建的,只能找到docker内部的目录,所以刚刚在docker-compose配置的数据卷上场
把这个目录整到/usr/local/docker_app/consul/consul_3/data/key下,server拷server的,client拷client的
然后开始配置TLS
server端
在数据卷(/usr/local/docker_app/consul/consul_1/config/)下创建tls.json,写入:
{
"verify_incoming":true,
"verify_outgoing": true,
"ca_file": "/consul/data/key/ca.pem",
"cert_file": "/consul/data/key/server/server.pem",
"key_file": "/consul/data/key/server/server.key"
}
- verify_incoming:所有传入连接都使用TLS
- verify_outgoing:此代理的所有传出连接都使用TLS
- ca_file:CA的PEM编码的证书颁发机构的文件路径(docker容器内目录)
- cert_file:PEM编码证书的文件路径
- key_file:PEM编码私钥的文件路径
官网说可以使用auto_encrypt自动将证书CA发到客户端,我试了,没成功,怀疑是docker容器的原因,不行就老老实实的配置
#复制到其他server
[root@coen config] cp tls.json ../../consul_2/config/
[root@coen config] cp tls.json ../../consul_3/config/
client端
在数据卷(/usr/local/docker_app/consul/consul_4/config/)下创建tls.json,写入:
{
"verify_incoming": false,
"verify_incoming_rpc": true,
"ports": {
"http": -1,
"https": 8500
},
"ca_file": "/consul/data/key/ca.pem",
"cert_file": "/consul/data/key/client/client.pem",
"key_file": "/consul/data/key/client/client.key"
}
verify_incoming配置成false,为啥?官网说,verify_incoming为true的话,在client UI页面要提供有效证书,给不了,就访问不了了,所以为false;verify_incoming_rpc为true,UI能不效验TLS提供服务,但RPC还是验证的,https端口8500
现在搭建好了,我们来试一试,先用http方式请求下数据
#先重启下consul集群
[root@coen docker_app] docker-compose down
[root@coen docker_app] docker-compose up -d
#http请求下
[root@coen docker_app] curl http://127.0.0.1:8500/v1/internal/ui/services
Client sent an HTTP request to an HTTPS server.
报错,说客户端发送的是http请求https服务,已经成功!现在用https请求下UI页面
[root@coen docker_app] curl https://localhost:8500/ui/ -k -I
HTTP/1.1 200 OK
Accept-Ranges: bytes
Content-Length: 6610
Content-Type: text/html; charset=utf-8
Last-Modified: Wed, 31 Jul 2019 01:42:30 GMT
Date: Wed, 31 Jul 2019 01:49:03 GMT
成功!可以在游览器https://192.168.28.128:8500 来访问Ul,游览器信任CA证书就行,“192.168.28.128”是我虚拟机内网地址,写你们自己的
配置ACL
server端
在数据卷(/usr/local/docker_app/consul/consul_1/config/)下创建acl.json,写入:
{
"acl":{
"enabled": true,
"default_policy": "deny",
"enable_token_persistence":true,
"tokens":{
"master":"saFKyW4CGQP+kv79dWYX6I/LK3iuHrVyuOfS+mxBNyg="
}
},
"datacenter":"dc1",
"primary_datacenter": "dc1"
}
- acl-enabled:开启acl
- acl-default_policy:把自己设置成白名单
- acl-enable_token_persistence:使用API设置将被保存到磁盘,并且当代理重新启动重新加载
- tokens-master:令牌密钥ID来引导ACL系统,(可以自定义,除了“master”还有很多种,可以在UI界面设置)
- datacenter:数据中心,默认“dc1”
- primary_datacenter:权威性的数据中心,提供它才能启用ACL,和tokens-master配合使用
#复制到其他server
[root@coen config] cp acl.json ../../consul_2/config/
[root@coen config] cp acl.json ../../consul_3/config/
client端
在数据卷(/usr/local/docker_app/consul/consul_4/config/)下创建tls.json,写入:
{
"acl":{
"enabled": true,
"default_policy": "deny",
"enable_token_persistence":false,
"tokens":{
"agent":"saFKyW4CGQP+kv79dWYX6I/LK3iuHrVyuOfS+mxBNyg="
}
},
"datacenter":"dc1",
"primary_datacenter": "dc1"
}
client端这里要设置tokens-agent,agen作用于客户端和服务器执行内部操作,我这为了图省事直接用sever的master了
线上不能这样,“master”是最高权限,正常流程先配置server的“master”,然后去UI生成权限低的“agent”,配置client端,然后重启client端,不重启server端,数据全部存储在server端,重启就没了
重启consul集群,访问UI,到ACL那
输入sever端配置的“token-agent”
可以看到这样的列表,初始有2个ACL,可以设置其他的,consul把ACL划分成“service_prefix”,“
key_prefix”,“node_prefix”三种"Policy"(策略),每个都有读写权限,配合“role”(角色)可以形成非常细的数据权限控制,查看官网了解
https://www.consul.io/docs/acl/index.html#acl-documentation
https://learn.hashicorp.com/consul/security-networking/production-acls
至此,consul集群搭完,这里只是演示一个数据中心,consul是多数据中心的,需要多数据中心要改一些配置,不要照搬硬套