自动生成HTTPS证书
Traefik
除了使用自有证书外,还支持Let's Encrypt
自动生成证书【6】。
要使用Let's Encrypt
自动生成证书,需要使用ACME
。需要在静态配置中定义 "证书解析器",Traefik
负责从ACME
服务器中检索证书。
然后,每个 "路由器 "被配置为启用TLS,并通过tls.certresolver配置选项与一个证书解析器关联。
Traefik
的ACME
验证方式主要有以下三种:
- tlsChallenge
- httpChallenge
- dnsChallenge
如果使用tlsChallenge
,则要求Let's Encrypt
到 Traefik 443
端口必须是可达的。如果使用httpChallenge
,则要求Let's Encrypt
到 Traefik 80
端口必须是可达的。如果使用dnsChallenge
,则需要对应的providers
[7]。
但是我们上面部署Traefik
的时候并没有把80和443端口暴露出来,要测试tlsChallenge
和httpChallenge
的话就必须暴露,下面我们更改一下my-value.yaml
,如下:
service: type: NodePort ingressRoute: dashboard: enabled: false ports: traefik: port: 9000 expose: true web: port: 8000 hostPort: 80 expose: true websecure: port: 8443 hostPort: 443 expose: true persistence: enabled: true name: data accessMode: ReadWriteOnce size: 5G storageClass: "openebs-hostpath" path: /data additionalArguments: - "--serversTransport.insecureSkipVerify=true" - "--api.insecure=true" - "--api.dashboard=true"
然后重新更新一下Traefik
,命令如下:
helm upgrade traefik -n traefik-ingress -f my-value.yaml .
现在我们就可以直接通过80或443端口进行访问了。
1、tlsChallenge
上面已经介绍过,要使用tlsChallenge
,必须能访问入口的443端口,现在我们入口已经放开,接下来就修改Traefik
的my-value.yaml
配置,如下:
...... deployment: initContainers: - name: volume-permissions image: busybox:1.31.1 command: ["sh", "-c", "chmod -Rv 600 /data/*"] volumeMounts: - name: data mountPath: /data additionalArguments: - "--serversTransport.insecureSkipVerify=true" - "--api.insecure=true" - "--api.dashboard=true" - "--certificatesresolvers.coolops.acme.email=coolops@163.com" - "--certificatesresolvers.coolops.acme.storage=/data/acme.json" - "--certificatesresolvers.coolops.acme.tlschallenge=true"
PS:这里需要将/data目录权限给更改一下,默认是0660,权限太大是不允许的。
然后我们创建一个ingressRoute
,如下:
# cat ingressrouteautotls.yaml apiVersion: traefik.containo.us/v1alpha1 kind: IngressRoute metadata: name: whoami-route-auto-tls spec: entryPoints: - websecure routes: - match: Host(`whoami3.coolops.cn`) kind: Rule services: - name: whoami port: 80 tls: certResolver: coolops
这时候我们访问https://whoami3.coolops.cn是可以正常使用证书的,如下:
2、httpChallenge
下面再使用httpChallenge
进行测试,修改my-value.yaml
配置文件如下:
...... deployment: initContainers: - name: volume-permissions image: busybox:1.31.1 command: ["sh", "-c", "chmod -Rv 600 /data/*"] volumeMounts: - name: data mountPath: /data additionalArguments: - "--serversTransport.insecureSkipVerify=true" - "--api.insecure=true" - "--api.dashboard=true" - "--certificatesresolvers.coolops.acme.email=coolops@163.com" - "--certificatesresolvers.coolops.acme.storage=/data/acme.json" - "--certificatesresolvers.coolops.acme.httpchallenge=true" - "--certificatesresolvers.coolops.acme.httpchallenge.entrypoint=web"
更新Traefik
过后,然后再创建一个ingressRoute
进行测试,YAML文件如下:
apiVersion: traefik.containo.us/v1alpha1 kind: IngressRoute metadata: name: whoami-route-auto-tls-http spec: entryPoints: - websecure routes: - match: Host(`whoami4.coolops.cn`) kind: Rule services: - name: whoami port: 80 tls: certResolver: coolops
然后使用https://whoami4.coolops.cn
,效果如下:
3、dnsChallenge
dnsChallenge
在使用上相对比较麻烦,因为需要配置对应的provider
,不过它可以生成通配符证书,这里以阿里云DNS【8】为例。
使用阿里DNS的前提是您的域名是在阿里云上面,不然在签署证书的时候会报错,如下:
Unable to obtain ACME certificate for domains \"*.coolops.cn\" : unable to generate a certificate for the domains [*.coolops.cn]: error: one or more domains had a problem:\n[*.coolops.cn] [*.coolops.cn] acme: error presenting token: alicloud: zone coolops.cn. not found in AliDNS for domain coolops.cn\n" providerName=coolops.acme
使用阿里云的 DNS 校验需要配置3个环境变量:ALICLOUD_ACCESS_KEY
、ALICLOUD_SECRET_KEY
、ALICLOUD_REGION_ID
,分别对应我们平时开发阿里云应用的时候的密钥,可以登录阿里云后台获取,由于这是比较私密的信息,所以我们用 Secret 对象来创建:
$ kubectl create secret generic traefik-alidns --from-literal=ALICLOUD_ACCESS_KEY=<aliyun ak> --from-literal=ALICLOUD_SECRET_KEY=<aliyun sk>--from-literal=ALICLOUD_REGION_ID=cn-beijing -n traefik-ingress
修改Traefik的my-value.yaml,如下:
...... additionalArguments: - "--serversTransport.insecureSkipVerify=true" - "--api.insecure=true" - "--api.dashboard=true" - "--certificatesresolvers.coolops.acme.email=coolops@163.com" - "--certificatesresolvers.coolops.acme.storage=/data/acme.json" - "--certificatesresolvers.coolops.acme.dnschallenge=true" - "--certificatesResolvers.coolops.acme.dnsChallenge.provider=alidns" envFrom: - secretRef: name: traefik-alidns
更新Traefik
过后,然后再创建一个ingressRoute
进行测试,YAML文件如下(由于coolops.cn不在阿里云上,所以换了一个域名):
apiVersion: traefik.containo.us/v1alpha1 kind: IngressRoute metadata: name: whoami-route-auto-tls-dns spec: entryPoints: - websecure routes: - match: Host(`whoami6.coolops.cn`) kind: Rule services: - name: whoami port: 80 tls: certResolver: coolops domains: - main: "*.coolops.cn"
然后访问域名后,就可以看到证书签署 成功,如下:
中间件的使用
在介绍Traefik
的核心概念的时候有提到一个请求匹配Rules
后,会经过一系列的Middleware
,再到具体的Services
上。这个Middleware
是什么呢?
Middleware
是Traefik 2.0
之后新增的功能,用户可以根据不通的需求来选择不同的Middleware来满足服务,提高了定制化的能力。
Traefik内置了很多不同功能的Middleware,主要是针对HTTP和TCP,HTTP占大部分[9],这里挑选几个比较常用的进行演示。
强制跳转HTTPS
强制跳转HTTPS是经常会配置的功能,这里还是以上没的whoami
应用为例。
1、创建一个HTTPS的ingressRoute
apiVersion: traefik.containo.us/v1alpha1 kind: IngressRoute metadata: name: whoami-route-auto-tls spec: entryPoints: - websecure routes: - match: Host(`whoami3.coolops.cn`) kind: Rule services: - name: whoami port: 80 tls: certResolver: coolops
2、定义一个跳转HTTPS的中间件
这里会用到RedirectScheme
的内置中间件,配置如下:
apiVersion: traefik.containo.us/v1alpha1 kind: Middleware metadata: name: redirect-https-middleware spec: redirectScheme: scheme: https
3、定义一个HTTP的ingressRoute,并使用Middleware
apiVersion: traefik.containo.us/v1alpha1 kind: IngressRoute metadata: name: whoami3-route spec: entryPoints: - web routes: - match: Host(`whoami3.coolops.cn`) kind: Rule services: - name: whoami port: 80 middlewares: - name: redirect-https-middleware
然后访问http://whoami3.coolops.cn
就会被强制跳转到https://whoami3.coolops.cn
。
去除请求路径前缀
有时候会遇到这么一个需求:
- 只有一个域名
- 相通过这个域名访问不同的应用
这种需求是非常常见的,在NGINX
中,我们可以配置多个Location
来定制规则,使用Traefik
也可以这么做。
但是定制不同的前缀后,由于应用本身并没有这些前缀,导致请求返回404
,这时候我们就需要对请求的path
进行处理,还是以whoami
应用为例。
1、创建一个带前缀的ingressRoute
apiVersion: traefik.containo.us/v1alpha1 kind: IngressRoute metadata: name: whoami7-route spec: entryPoints: - web routes: - match: Host(`whoami7.coolops.cn`) && PathPrefix('/coolops') kind: Rule services: - name: whoami port: 80
我们现在访问是会返回404
状态的。
2、定义去除前缀的中间件
apiVersion: traefik.containo.us/v1alpha1 kind: Middleware metadata: name: prefix-coolops-url-middleware spec: stripPrefix: prefixes: - /coolops
3、修改上面的ingressRoute,应用中间件
apiVersion: traefik.containo.us/v1alpha1 kind: IngressRoute metadata: name: whoami7-route spec: entryPoints: - web routes: - match: Host(`whoami7.coolops.cn`) && PathPrefix('/coolops') kind: Rule services: - name: whoami port: 80 middlewares: - name: prefix-coolops-url-middleware
然后就可以正常访问了。
添加IP白名单
在工作中,有一些URL并不希望对外暴露,比如prometheus、grafana等的url,这时候我们希望通过白名单IP来达到需求,就可以使用Traefik
中的ipWhiteList
中间件来完成。
1、定义白名单IP的中间件
apiVersion: traefik.containo.us/v1alpha1 kind: Middleware metadata: name: ip-white-list-middleware spec: ipWhiteList: sourceRange: - 127.0.0.1/32 - 192.168.100.180
然后将中间件应用到对应的Rules上,就可以完成白名单功能。
除了上面的功能,Traefik内置Middleware还支持很多其他功能,比如限流、认证鉴权等,可以通过引用【9】进行查看。
暴露TCP服务
Traefik 2.0支持暴露TCP,这里以Redis为例。
1、部署一个Redis服务
apiVersion: apps/v1 kind: Deployment metadata: name: redis spec: selector: matchLabels: app: redis template: metadata: labels: app: redis spec: containers: - name: redis image: redis:5.0.14 ports: - containerPort: 6379 protocol: TCP --- apiVersion: v1 kind: Service metadata: name: redis spec: ports: - port: 6379 targetPort: 6379 selector: app: redis
2、暴露Redis端口
暴露TCP端口使用的是SNI【10】,而SNI又是依赖TLS的,所以我们需要配置证书才行,但是如果没有证书的话,我们可以使用通配符*
进行配置。
(1)、添加一个redis的entrypoints
修改Traefik
的部署文件my-value.yaml
,添加如下内容:
ports: traefik: port: 9000 expose: true web: port: 8000 hostPort: 80 expose: true websecure: port: 8443 hostPort: 443 expose: true redis: port: 6379 containerPort: 6379 hostPort: 6379 additionalArguments: - "--entryPoints.redis.address=:6379" - "--serversTransport.insecureSkipVerify=true" - "--api.insecure=true" - "--api.dashboard=true" - "--certificatesresolvers.coolops.acme.email=coolops@163.com" - "--certificatesresolvers.coolops.acme.storage=/data/acme.json" - "--certificatesresolvers.coolops.acme.httpchallenge=true" - "--certificatesresolvers.coolops.acme.httpchallenge.entrypoint=web"
在启动参数中添加--entryPoints.redis.address=:6379
用来指定entrypoint。
(2)、创建ingressRoute进行对外暴露
apiVersion: traefik.containo.us/v1alpha1 kind: IngressRouteTCP metadata: name: redis-traefik-tcp spec: entryPoints: - redis routes: - match: HostSNI(`*`) services: - name: redis port: 6379
然后可以使用客户端工具进行Redis的操作了。
# redis-cli -h redis.coolops.cn redis.coolops.cn:6379> set a b OK redis.coolops.cn:6379> get a "b" redis.coolops.cn:6379>