mindxdl--common--web_cert_utils.go
// Copyright (c) 2021. Huawei Technologies Co., Ltd. All rights reserved.
// Package common this file define WebCertUtil
package common
import (
"crypto/tls"
"crypto/x509"
"encoding/pem"
"errors"
"fmt"
"github.com/gin-gonic/gin"
"huawei.com/npu-exporter/hwlog"
"huawei.com/npu-exporter/limiter"
"huawei.com/npu-exporter/utils"
"io/ioutil"
"net/http"
"strconv"
"strings"
"time"
)
const keyLength = 4096
var webCert *WebCertUtil
// WebCertUtil WebCertUtil
type WebCertUtil struct {
*CertificateUtils
}
// NewWebCertUtil NewWebCertUtil
func NewWebCertUtil(dnsName, dirName string, overdueTime int) *WebCertUtil {
ws := &WebCertUtil{
CertificateUtils: NewCertificateUtils(dnsName, dirName, overdueTime),
}
if err := utils.MakeSureDir(ws.KeyStore); err != nil {
hwlog.RunLog.Fatal(err)
}
return ws
}
// GetWebCertUtil return webCert
func GetWebCertUtil() *WebCertUtil {
return webCert
}
// CheckCertValidityPeriod CheckCertValidityPeriod
func (ws *WebCertUtil) CheckCertValidityPeriod(interval time.Duration) {
hwlog.RunLog.Info("start cert period check...")
ticker := time.NewTicker(interval)
defer ticker.Stop()
hasTask := false
for {
_, ok := <-ticker.C
if !ok {
return
}
if hasTask {
continue
}
ws.Lock.RLock()
if ws.Cert == nil {
ws.Lock.RUnlock()
continue
}
x509Cert, err := x509.ParseCertificate(ws.Cert.Certificate[0])
if err != nil {
ws.Lock.RUnlock()
continue
}
err = utils.CheckValidityPeriodWithError(x509Cert, ws.OverdueTime)
ws.Lock.RUnlock()
if err == nil {
continue
}
hwlog.RunLog.Warn(err)
go func() {
hasTask = true
defer func() {
hasTask = false
hwlog.RunLog.Info("apply for a new certificate success")
}()
hwlog.RunLog.Info("apply for a new certificate because the certificate has expired")
if err = ws.ApplyForCertificateByRequest(); err != nil {
hwlog.RunLog.Error(err)
}
}()
}
}
// GetCaByRequest get ca by request
func (ws *WebCertUtil) GetCaByRequest() ([]byte, error) {
caByte, err := DefaultClsMgrClient.GetRootCertificate()
if err != nil {
return nil, err
}
hwlog.RunLog.Info("succeeded in getting ca certificate by request")
if err = ioutil.WriteFile(ws.CaStore, caByte, utils.RWMode); err != nil {
return nil, errors.New("write caBytes to file failed")
}
hwlog.RunLog.Info("succeeded in saving ca certificate to file")
ws.CaBytes = caByte
return caByte, nil
}
// ApplyForCertificateByRequest apply for certificate by request
func (ws *WebCertUtil) ApplyForCertificateByRequest() error {
certPem, err := DefaultClsMgrClient.ApplyForCertificatePemByte(ws.DNSName, ws.CaBytes, ws.PrivateKey)
if err != nil {
return err
}
hwlog.RunLog.Info("succeeded in getting certificate by request")
derStream := x509.MarshalPKCS1PrivateKey(ws.PrivateKey)
block := &pem.Block{
Type: RSAPrivateKey,
Bytes: derStream,
}
keyPem := pem.EncodeToMemory(block)
tlsCert, err := utils.ValidateCertPair(certPem, keyPem, false, ws.OverdueTime)
if err != nil {
return err
}
if err = ioutil.WriteFile(ws.CertStore, certPem, utils.RWMode); err != nil {
return errors.New("write certBytes to file failed ")
}
hwlog.RunLog.Info("succeeded in saving certificate to file")
ws.Lock.RLock()
defer ws.Lock.RUnlock()
ws.refreshCertStatus(tlsCert)
ws.Cert = tlsCert
return nil
}
func (ws *WebCertUtil) refreshCertStatus(tlsCert *tls.Certificate) {
// clear cert status record
ws.ClearCertificateMap()
caCert, err := utils.LoadCertsFromPEM(ws.CaBytes)
if err == nil {
// refresh ca record
err = utils.AddToCertStatusTrace(caCert)
}
if err != nil {
hwlog.RunLog.Error("prepare refresh ca info failed: " + err.Error())
}
x509Cert, err := x509.ParseCertificate(tlsCert.Certificate[0])
if err == nil {
// refresh certificate record
err = utils.AddToCertStatusTrace(x509Cert)
}
if err != nil {
hwlog.RunLog.Error("prepare refresh certificate info failed: " + err.Error())
}
hwlog.RunLog.Info("succeeded in refresh ca/cert info")
}
// SetHTTPSServer set http server config for one or two way auth
func (ws *WebCertUtil) SetHTTPSServer(s *http.Server, concurrency, maxConcurrency int,
cipherSuites []uint16, ginObj *gin.Engine) error {
tlsConfig, err := utils.NewTLSConfigV2(ws.CaBytes, *ws.Cert, cipherSuites)
if err != nil {
return err
}
tlsConfig.Certificates = nil
tlsConfig.GetCertificate = ws.GetCertificateFunc()
s.Handler = limiter.NewLimitHandler(concurrency, maxConcurrency, utils.Interceptor(ginObj, ws.CrlList), false)
s.TLSConfig = tlsConfig
return nil
}
// ReApplyCertificate reapply certificate
func (ws *WebCertUtil) ReApplyCertificate(algorithm int) error {
hwlog.RunLog.Info("prepare to reapply a new certificate")
if ws.PrivateKey == nil {
if _, err := ws.GenerateRSAPrivateKey(keyLength, algorithm); err != nil {
return err
}
}
if err := ws.ApplyForCertificateByRequest(); err != nil {
return err
}
return nil
}
// GetRequestClient get http client for request
func (ws *WebCertUtil) GetRequestClient(authMode string) (*http.Client, error) {
// https auth two way
if authMode == TwoWay {
requestClient, err := ws.GetTwoWayAuthRequestClient()
if err != nil {
return nil, err
}
return requestClient, nil
}
// https auth one way
pool, err := x509.SystemCertPool()
if err != nil {
return nil, fmt.Errorf("cannot get system trusted certificates pool: %w", err)
}
if !pool.AppendCertsFromPEM(ws.CaBytes) {
return nil, fmt.Errorf("failed to append to certificates pool")
}
c := &http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
RootCAs: pool,
},
},
}
return c, nil
}
// InitCert init cert and ca
func InitCert(sp *ServerParam) error {
ws := NewWebCertUtil(sp.DNSName, sp.DirName, sp.OverdueTime)
var reApply bool
var caBytes []byte
// load ca
_, err := ws.LoadCAOnStart(sp.AuthMode)
if err != nil && strings.Contains(err.Error(), ReApply) {
reApply = true
}
// reapply ca
if reApply {
caBytes, err = ws.GetCaByRequest()
if len(caBytes) == 0 || err != nil {
return err
}
reApply = false
}
if err != nil {
return err
}
// load cert and private key
_, err = ws.LoadCertAndKeyOnStart(sp.EncryptAlgorithm)
if err != nil && strings.Contains(err.Error(), ReApply) {
reApply = true
}
// reapply cert
if reApply {
if err = ws.ReApplyCertificate(sp.EncryptAlgorithm); err != nil {
return err
}
}
if err != nil {
return err
}
// init global WebCertUtil
webCert = ws
return nil
}
// StartServerListen StartServerListen
func StartServerListen(sp *ServerParam, engine *gin.Engine) {
s := &http.Server{
ReadTimeout: sp.ReadTimeOut * time.Second,
WriteTimeout: sp.WriteTimeOut * time.Second,
Addr: sp.IP + ":" + strconv.Itoa(sp.Port),
Handler: limiter.NewLimitHandler(sp.Concurrency, sp.MaxConcurrency, engine, false),
}
// http
if sp.EnableHTTP {
// http
hwlog.RunLog.Warn("Service started with an insecure http server enabled")
if err := s.ListenAndServe(); err != nil {
hwlog.RunLog.Error("Http server error and stopped")
}
return
}
// init web cert util
err := InitCert(sp)
if err != nil {
hwlog.RunLog.Error(err)
return
}
ParseTLSParams(sp)
wc := GetWebCertUtil()
if err = wc.SetHTTPSServer(s, sp.Concurrency, sp.MaxConcurrency, sp.CipherSuites,
engine); err != nil {
hwlog.RunLog.Error(err)
return
}
hwlog.RunLog.Info("start https server now...")
// start certificate period check
go wc.CheckCertValidityPeriod(sp.CheckCertPeriod)
if err = s.ListenAndServeTLS("", ""); err != nil {
hwlog.RunLog.Error("Https server error by: %s and stopped", err.Error())
}
}
mindxdl--common--web_cert_utils.go的更多相关文章
- Socket聊天程序——Common
写在前面: 上一篇记录了Socket聊天程序的客户端设计,为了记录的完整性,这里还是将Socket聊天的最后一个模块--Common模块记录一下.Common的设计如下: 功能说明: Common模块 ...
- angularjs 1 开发简单案例(包含common.js,service.js,controller.js,page)
common.js var app = angular.module('app', ['ngFileUpload']) .factory('SV_Common', function ($http) { ...
- Common Bugs in C Programming
There are some Common Bugs in C Programming. Most of the contents are directly from or modified from ...
- ANSI Common Lisp Practice - My Answers - Chatper - 3
Ok, Go ahead. 1 (a) (b) (c) (d) 2 注:union 在 Common Lisp 中的作用就是求两个集合的并集.但是这有一个前提,即给的两个列表已经满足集合的属性了.具体 ...
- [LeetCode] Lowest Common Ancestor of a Binary Tree 二叉树的最小共同父节点
Given a binary tree, find the lowest common ancestor (LCA) of two given nodes in the tree. According ...
- [LeetCode] Lowest Common Ancestor of a Binary Search Tree 二叉搜索树的最小共同父节点
Given a binary search tree (BST), find the lowest common ancestor (LCA) of two given nodes in the BS ...
- [LeetCode] Longest Common Prefix 最长共同前缀
Write a function to find the longest common prefix string amongst an array of strings. 这道题让我们求一系列字符串 ...
- 48. 二叉树两结点的最低共同父结点(3种变种情况)[Get lowest common ancestor of binary tree]
[题目] 输入二叉树中的两个结点,输出这两个结点在数中最低的共同父结点. 二叉树的结点定义如下: C++ Code 123456 struct BinaryTreeNode { int ...
- 动态规划求最长公共子序列(Longest Common Subsequence, LCS)
1. 问题描述 子串应该比较好理解,至于什么是子序列,这里给出一个例子:有两个母串 cnblogs belong 比如序列bo, bg, lg在母串cnblogs与belong中都出现过并且出现顺序与 ...
- 【leetcode】Longest Common Prefix
题目简述: Write a function to find the longest common prefix string amongst an array of strings. 解题思路: c ...
随机推荐
- Linux虚拟机 RHEL8.0安装步骤
一. 创建空白虚拟机 1.打开 VMware 虚拟机软件依次选择新建虚拟机并选择选择"自定义" 自定义功能更加全面,典型就是比较简单的配置 2.选择对应的 VMware 版本,此则 ...
- git cherry-pick 总结
git cherry-pick cherry-pick : 精心挑选,挑选一个我们需要的 commit 进行操作.它可以用于将在其他分支上的 commit 移植到当前的分支. 用法: // 复制com ...
- Java开发学习(三十一)----Maven属性与版本管理
一.属性 1.1 问题分析 如下图所示 你会发现,如果现在想更新Spring的版本,你会发现依然需要更新多个jar包的版本,这样的话还是有可能出现漏改导致程序出问题,而且改起来也是比较麻烦. 问题清楚 ...
- 【SQLServer】max worker threads参数配置
查看和设置max worker threads USE master; //选中你想设置max worker threads的数据库.master表示在实例级别进行设置 GO EXEC sp_conf ...
- RabbitMQ之消息模式简单易懂,超详细分享~~~
前言 上一篇对RabbitMQ的流程和相关的理论进行初步的概述,如果小伙伴之前对消息队列不是很了解,那么在看理论时会有些困惑,这里以消息模式为切入点,结合理论细节和代码实践的方式一起来学习. 正文 常 ...
- 02-MyBatisPlus入门
快速开始参考:https://baomidou.com/pages/226c21/ 测试项目: mybatis_plus 数据库:mybatis_plus 一.创建并初始化数据库 1.创建数据库: m ...
- 如何使用Arthas定位问题
在我们日常的工作中,经常会遇到一些线上才会遇到的问题.Arthas无疑是我们在工作中,定位线上问题的神奇.下面,我将介绍一下我们在工作中经常用到的一些功能. dashboard 首先我们可以通过das ...
- HTTPS安全加固配置最佳实践指南
转载自:https://www.bilibili.com/read/cv16067729?spm_id_from=333.999.0.0 0x02 HTTPS安全加固指南 描述: 当你的网站上了 HT ...
- 在 Kubernetes 上运行高可用的 Kafka 集群
转载自:https://www.qikqiak.com/post/deploy-kafka-ha-on-k8s/ Apache Kafka 是目前最流行的分布式消息发布订阅系统,虽然 Kafka 非常 ...
- Rook Toolbox
官方文档:https://rook.io/docs/rook/v1.8/ceph-toolbox.html Rook工具箱是一个包含用于Rook调试和测试的常用工具的容器.工具箱基于CentOS,因此 ...