欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

golang 实现无域名的HTTPS服务器

程序员文章站 2022-07-12 21:59:11
...

场景是这样子的:我们有一个自己搭建的CA来签发证书,CA给我们的服务器签发证书.现在整个产品还处于内部开发阶段,服务器只有一个内网IP,没有域名.搭建WEB服务使用了go语言的echo库.

那么会遇到这样的一个问题:一般来说,服务器的证书common name字段都是服务器的host name/domain name,但是在我们的这个场景下,服务器只有IP,如果服务器证书的common name 直接填入IP地址的话,那么会报错:

x509: cannot validate certificate for 127.0.0.1 because it doesn't contain any IP SANs

解决方案主要参考了:

https://cabforum.org/guidance-ip-addresses-certificates/

https://*.com/questions/2043617/is-it-possible-to-have-ssl-certificate-for-ip-address-not-domain-name

https://*.com/questions/1095780/are-ssl-certificates-bound-to-the-servers-ip-address

证书内部有一个subjet alternative name扩展字段,也就是上面的那个错误中提到的SANs,如果说证书里面使用IP不使用域名的话,证书的common name和SAN都要写入IP地址(证书使用IP而不使用域名是不推荐的,我们这里只是为了内部开发调试的目的).

具体的实现参考了:

https://github.com/jcbsmpsn/golang-https-example

也就是说,签发证书的命令是:

openssl req \
    -newkey rsa:2048 \
    -nodes \
    -days 3650 \
    -x509 \
    -keyout ca.key \
    -out ca.crt \
    -subj "/CN=*"
openssl req \
    -newkey rsa:2048 \
    -nodes \
    -keyout server.key \
    -out server.csr \
    -subj "/C=GB/ST=London/L=London/O=Global Security/OU=IT Department/CN=*"
openssl x509 \
    -req \
    -days 365 \
    -sha256 \
    -in server.csr \
    -CA ca.crt \
    -CAkey ca.key \
    -CAcreateserial \
    -out server.crt \
    -extfile <(echo subjectAltName = IP:127.0.0.1)

最后一行把IP地址写入SAN,生成证书.

附上客户端和服务器的Demo代码:

服务器

package main

import (
	"crypto/tls"
	"net/http"

	//	"golang.org/x/crypto/acme/autocert"
	//	"log"
	"fmt"

	"github.com/labstack/echo"
	"github.com/labstack/echo/middleware"
)

const (
	server_crt = "server.crt"
	server_key = "server.key"
)

func main() {
	e := echo.New()
	e.Use(middleware.Recover())
	e.GET("/", func(c echo.Context) error {
		return c.HTML(http.StatusOK, `
			<h1>Welcome to Echo!</h1>
			<h3>TLS certificates automatically installed from Let's Encrypt :)</h3>
		`)
	})
	e.TLSServer.TLSConfig = new(tls.Config)
	//TLSConfig
	certificate, err := tls.LoadX509KeyPair(server_crt, server_key)
	if err != nil {
		fmt.Println(err.Error())
		return
	}
	// Create a certificate pool from the certificate authority

	e.TLSServer.TLSConfig.Certificates = []tls.Certificate{certificate}

	e.TLSServer.Addr = ":10000"

	e.StartServer(e.TLSServer)
}

客户端

func main() {
	pool := x509.NewCertPool()
	caCertPath := "ca.crt"

	caCrt, err := ioutil.ReadFile(caCertPath)
	if err != nil {
		fmt.Println("ReadFile err:", err)
		return
	}
	pool.AppendCertsFromPEM(caCrt)

	tr := &http.Transport{
		TLSClientConfig: &tls.Config{RootCAs: pool},
	}
	client := &http.Client{Transport: tr}
	resp, err := client.Get("https://127.0.0.1:10000")
	if err != nil {
		fmt.Println("Get error:", err)
		return
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	fmt.Println(string(body))
}

 

相关标签: tls