使用Functiongraph同步Cert-manager证书到ELB,实现证书定期自动轮转

举报
欧力给大君 发表于 2024/01/10 00:34:05 2024/01/10
【摘要】 使用开源letsencrypt签发证书时,cert-manager可以帮助实现证书管理及证书周期性签发、更新等功能,实现证书定期轮转。 在此基础上,当叠加使用WAF或者ELB+WAF对应用进行安全防护时,如何动态将letsencrypt签发的证书自动同步到WAF或者ELB? 本文利用Functiongraph,实现证书自动同步,进而实现证书的自动轮转功能。

一. 使用Cert-manager自动轮转Prestashop网站证书,证书在Nginx生效

架构图

 

环境准备

# 创建CCE集群和node节点。

# 申请公网EIP,EIP绑定到node节点,node节点可以访问外网下载资源

# 申请TCP/UDP类型的ELB,用于绑定ingress

# 安装ingress插件,数量和规格都可自行调整

# 登录node节点,配置kubectl

工具准备

安装helm

# 登录配置了kubectl的Node节点

cd /opt

wget https://get.helm.sh/helm-v3.13.2-linux-amd64.tar.gz

tar -zxvf helm-v3.13.2-linux-amd64.tar.gz

cd linux-amd64/

cp -f helm /usr/local/bin/

 

安装Git

yum install git

安装cert-manager及ClusterIssuer

# install cert-manager

kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.12.0/cert-manager.yaml

 

# install cert-manager-webhook-huaweidns

kubectl apply -f https://github.com/innoai-tech/cert-manager-webhook-huaweidns/releases/download/latest/cert-manager-webhook-huaweidns.yaml

 

# install ClusterIssuer(修改红色部分的参数)

新建ClusterIssuer.yaml文件,内容如下

apiVersion: cert-manager.io/v1

kind: ClusterIssuer

metadata:

  name: letsencrypt-prod

spec:

  acme:

    email: <email>

    preferredChain: ''

    privateKeySecretRef:

      name: letsencrypt-prod

    server: https://acme-v02.api.letsencrypt.org/directory

    solvers:

      - dns01:

          webhook:

            config:

              appKey: <appKey>    # iam用户AK

              appSecret: <appSecret>   # iam用户SK

              region: <region>  # 域名所在 region

              zoneId: <zoneId>  # 域名 zoneId

            groupName: acme.innoai.tech

            solverName: huawei-dns

 

 

其中,region参数填写CCE集群所在的regionID,zoneId通过API Explorer 查询

文件准备好后,执行命令创建

kubectl apply -f ClusterIssuer.yaml

本章节参考资料:https://www.cnblogs.com/gshelldon/p/17787386.html

 

安装prestashop

# 下载包

mkdir /opt/ bitnami

cd /opt/bitnami/

git clone https://github.com/bitnami/charts.git

cp /opt/bitnami/charts/prestashop/values.yaml  /opt/bitnami/

chmod 777 values.yaml

#修改values.yaml

  # prestashop及DB的用户名密码根据需要自行修改

  # pvc卷声明必须修改(增加红色字体部分)

persistence:

  ## @param persistence.enabled Enable persistence using PVC

  ##

  enabled: true

  ## @param persistence.storageClass PrestaShop Data Persistent Volume Storage Class

  ## If defined, storageClassName: <storageClass>

  ## If set to "-", storageClassName: "", which disables dynamic provisioning

  ## If undefined (the default) or set to null, no storageClassName spec is

  ##   set, choosing the default provisioner.  (gp2 on AWS, standard on

  ##   GKE, AWS & OpenStack)

  ##

  annotations:

    everest.io/disk-volume-type: SAS

    volume.beta.kubernetes.io/storage-provisioner: everest-csi-provisioner

    volume.kubernetes.io/storage-provisioner: everest-csi-provisioner

  storageClass: "csi-disk"

 

  ## @param persistence.accessModes PVC Access Mode for PrestaShop volume

  ##

  accessModes:

    - ReadWriteOnce

  ## @param persistence.size PVC Storage Request for PrestaShop volume

  ##

  size: 8Gi

# service type必须修改,默认安装为LB类型,这里需要修改成集群内访问

service:

  ## @param service.type Kubernetes Service type

  ##

  type: ClusterIP

# Ingress开关必须修改,默认ingress是false,这里需要打开,在ingress层做证书校验

ingress:

  ## @param ingress.enabled Enable ingress controller resource

  ##

  enabled: true

。。此处省略其他默认参数。。。

hostname:  <自定义域名>

annotations:

     kubernetes.io/ingress.class: nginx

     #定义证书签发者,这里设置后 cert-manager会自动生成证书

     cert-manager.io/cluster-issuer: letsencrypt-prod

     #定义证书有效时间,到期会自动生成和替换

     cert-manager.io/renew-before: 1h  

tls: true

 

 

#安装prestashop

helm install my-release oci://registry-1.docker.io/bitnamicharts/prestashop  -f values.yaml

 

# 检查各组件状态

到CCE Console,查看负载、服务、服务路由、秘钥等状态是否正常,如有异常查看日志。

秘钥状态可登录node节点,执行命令查看ready状态是否为True:kubectl get cert -A

 

# 登录Prestashop管理员界面,修改TLS开关

http://<你的网站域名>/administration

 

备注:登录Node节点,查看管理员账号和密码:

  • 账号是yaml配置文件中的prestashopEmail参数
  • 密码通过如下命令查询:

          export APP_PASSWORD=$(kubectl get secret --namespace default my-release-prestashop -o jsonpath="{.data.prestashop-password}" | base64 -d)

          echo $APP_PASSWORD

配置DNS域名解析

添加记录集

IP配置为ELB的公网IP

 

 

测试

登录Node节点,执行命令

wget https://<你的网站域名>

 

或者打开浏览器,输入

https://<你的网站域名>

查看证书

设置证书定期轮转时间

参考https://cert-manager.io/docs/usage/ingress/,配置证书重置策略

更新Nginx的路由yaml文件,添加如下字段:

cert-manager.io/renew-before: 360h

证书会在过期前的360h自动更新。

可以登录CCE Node节点,查看证书的过期时间

 

 

二. 使用ELB模式WAF防护Prestashop网站,证书在ELB生效

架构图

资源准备

购买7层ELB

使用与CCE相同region, VPC和子网,创建最小规格的应用型独享ELB,创建时选择带公网EIP

在ELB服务下创建证书

获取证书

Prestashop及Cert-manager网站在CCE部署成功后,CCE容器的“配置与秘钥”界面可以看到,Prestashop网站的证书被Cert-manager定期更新,在这里复制对应证书的内容。

创建证书

ELB服务界面下,点证书管理,选择创建证书,此处创建证书用于https监听器

创建监听器

创建http监听器,创建时不添加后端服务器

创建https监听器,创建时不添加后端服务器,证书参考“在ELB服务下创建证书”章节

购买独享WAF

使用与CCE相同region, VPC, 子网, 安全组,创建最小规格的单实例独享WAF

添加WAF实例作为7层ELB的后端服务器

查看7层ELB后端服务器监控检查结果

默认健康检查的协议和端口与监听器的配置一样,如果健康检查失败,可以修改健康检查的协议为TCP

 

在WAF服务下创建证书(使用ELB+WAF模式时此步不需要)

在WAF服务界面,找到“对象管理”“证书管理”,添加证书

此处添加的证书,与Cert-manager定期颁发的证书保持一致

 

添加防护网站

在WAF服务界面,找到“网站设置”,添加防护网站,选择独享WAF模式,填写参数

修改DNS域名解析

在ELB服务界面,查看7层ELB的公网IP地址

在DNS服务界面,修改域名记录集的IP值

域名修改后,访问网站域名至少20次,触发WAF工作。

查看网站接入状态

 

三. 使用FunctionGraph定期更新ELB证书

架构图

依赖包准备

制作ELB依赖包

参考https://support.huaweicloud.com/devg-functiongraph/functiongraph_02_0616.html,制作ELB的python3.9依赖包

 

制作ELB依赖包案例:

cd /opt

wget https://github.com/huaweicloud/huaweicloud-sdk-python-v3/archive/refs/heads/master.zip

unzip master.zip

cd huaweicloud-sdk-python-v3-master/huaweicloud-sdk-elb/

 

python3 setup.py install --root /tmp/pyelb

cd /tmp/pyelb/

cd usr/local/python3/lib/python3.9/site-packages/

zip -rq pyelb.zip *

obsutil cp pyelb.zip obs://wangji-test/

 

在Functiongraph服务界面创建依赖包

 

制作kubernetes依赖包(不是CCE SDK)

参考https://support.huaweicloud.com/devg-functiongraph/functiongraph_02_0616.html,制作kubernetes的python3.9依赖包

mkdir /tmp/kubectl

cd /tmp/kubectl/

pip3 install kubernetes --root /tmp/kubectl

cd usr/local/python3/lib/python3.9/site-packages/

zip -rq kubernetes.zip *

mv kubernetes.zip /opt/

cd /opt

obsutil cp kubernetes.zip  obs://wangji-test/

 

制作WAF依赖包(如果不用ELB模式的WAF,同步证书到WAF)

 

配置K8s事件日志采集到LTS

 

Functiongraph函数

创建空白函数

进入Functiongraph console,创建空白函数,选择python3.9开发语言,委托需选择具有LTS权限的

设置函数相关配置

  • 触发器设置

创建LTS触发器,选择K8s事件日志所在的日志组和日志流

  • 确认权限配置

  • 超时时间设置

  • 网络配置确认

Functiongraph可以通过VPC或者EIP访问CCE资源,采用EIP访问时,CCE的集群需要关联EIP,kubectl配置项需要包含externalCluster的信息。

  • 环境变量设置
  1. 访问ELB的资源,这里采用ELB的SDK,需要配置鉴权参数AK/SK,及待更新的ELB对象ID参数

  1. 访问CCE的资源,这里采用的开源kubernetes的SDK,通过配置文件的方式设置环境变更

 

新建名称为config的配置文件,文件内容从CCE界面的kubectl配置获取。

注意访问CCE资源可采用VPC或者EIP方式,如果采用VPC方式,需要在函数设置->网络配置界面 打开VPC访问开关;如果采用EIP方式,需要为CCE集群绑定EIP,并获取带有externalCluster信息的kubectl配置文件。

 

  1. 访问Cert-manager定期更新的证书名称及名空间,通过配置文件的方式设置环境变量

 

 

函数代码

对LTS日志过滤,判断是否为Cert更新证书事件

import base64

import json

 

def handler(event, context):

    certificate_name = context.getUserData('certificate_name', '').strip()

    namespace_name = context.getUserData('namespace_name', '').strip()

 

    encodingData = event["lts"]["data"]

    data = base64.b64decode(encodingData)  

    body = json.loads(data)

    logs = body['logs']

    messages = json.loads(logs)

   

    for line in messages:

        lineStr = json.dumps(line)

        message_i = line["message"]

        message_i = json.loads(message_i)

        print(message_i)

        print(message_i['resource_name'])

        if message_i['resource_name'] == certificate_name and message_i['namespace'] == namespace_name:

            print("cert has event log...")

 

获取certificate证书内容

# coding: utf-8

from huaweicloudsdkcore.auth.credentials import BasicCredentials

from huaweicloudsdkcore.exceptions import exceptions

from kubernetes import client, config, watch

import os

import base64

 

    # Set config file path

    config_file = "/opt/function/code/config"

    config.load_kube_config(config_file=config_file)

 

    client_v1 = client.CoreV1Api()

    result = client_v1.read_namespaced_secret(name=certificate_name, namespace=namespace_name)

   

    #print("print secret detail...")

    #print(result.data)

    certificate = base64.b64decode(result.data['tls.crt'])

    private_key = base64.b64decode(result.data['tls.key'])

 

更新ELB证书

from huaweicloudsdkcore.auth.credentials import BasicCredentials

from huaweicloudsdkelb.v2.region.elb_region import ElbRegion

from huaweicloudsdkcore.exceptions import exceptions

from huaweicloudsdkelb.v2 import *

 

    # update elb cert

    ak = context.getUserData('CLOUD_SDK_AK', '').strip()

    sk = context.getUserData('CLOUD_SDK_SK', '').strip()

    elb_certificate_id = context.getUserData('elb_certificate_id', '').strip()

    credentials = BasicCredentials(ak, sk) \

 

    elb_client = ElbClient.new_builder() \

        .with_credentials(credentials) \

        .with_region(ElbRegion.value_of("ap-southeast-1")) \

        .build()

   

    print("update elb secret...")

 

    try:

        request = UpdateCertificateRequest()

        request.certificate_id = elb_certificate_id

        request.body = UpdateCertificateRequestBody(

            private_key=private_key,

            certificate=certificate

        )

        response = elb_client.update_certificate(request)

        print(response)

    except exceptions.ClientRequestException as e:

        print(e.status_code)

        print(e.request_id)

        print(e.error_code)

        print(e.error_msg)

 

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。