golang 实现无域名的HTTPS服务器

场景是这样子的:我们有一个自己搭建的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://stackoverflow.com/questions/2043617/is-it-possible-to-have-ssl-certificate-for-ip-address-not-domain-name

https://stackoverflow.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, `
			

Welcome to Echo!

TLS certificates automatically installed from Let's Encrypt :)

`) }) 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))
}

 

你可能感兴趣的:(网络,golang)