Skip to content

Commit

Permalink
add grpc api tls support
Browse files Browse the repository at this point in the history
  • Loading branch information
p4gefau1t committed May 20, 2020
1 parent e21d110 commit 7b636d3
Show file tree
Hide file tree
Showing 8 changed files with 83 additions and 12 deletions.
14 changes: 13 additions & 1 deletion api/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package api

import (
"context"
"crypto/tls"
"net"

"github.com/p4gefau1t/trojan-go/common"
Expand All @@ -10,6 +11,7 @@ import (
"github.com/p4gefau1t/trojan-go/proxy"
"github.com/p4gefau1t/trojan-go/stat"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
)

type ClientAPI struct {
Expand Down Expand Up @@ -52,7 +54,17 @@ func (s *ClientAPI) GetTraffic(ctx context.Context, req *GetTrafficRequest) (*Ge
}

func RunClientAPI(ctx context.Context, config *conf.GlobalConfig, auth stat.Authenticator) error {
server := grpc.NewServer()
var server *grpc.Server
if config.API.APITLS {
creds := credentials.NewTLS(&tls.Config{
ClientAuth: tls.RequireAndVerifyClientCert,
Certificates: config.TLS.KeyPair,
ClientCAs: config.TLS.ClientCertPool,
})
server = grpc.NewServer(grpc.Creds(creds))
} else {
server = grpc.NewServer()
}
service := &ClientAPI{
ctx: ctx,
auth: auth,
Expand Down
1 change: 1 addition & 0 deletions api/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (

"github.com/p4gefau1t/trojan-go/common"
"github.com/p4gefau1t/trojan-go/conf"
_ "github.com/p4gefau1t/trojan-go/log/golog"
"github.com/p4gefau1t/trojan-go/stat/memory"
"google.golang.org/grpc"
)
Expand Down
15 changes: 14 additions & 1 deletion api/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package api

import (
"context"
"crypto/tls"
"io"
"net"

Expand All @@ -11,6 +12,7 @@ import (
"github.com/p4gefau1t/trojan-go/proxy"
"github.com/p4gefau1t/trojan-go/stat"
grpc "google.golang.org/grpc"
"google.golang.org/grpc/credentials"
)

type ServerAPI struct {
Expand Down Expand Up @@ -152,7 +154,18 @@ func (s *ServerAPI) ListUsers(req *ListUserRequest, stream TrojanServerService_L
}

func RunServerAPI(ctx context.Context, config *conf.GlobalConfig, auth stat.Authenticator) error {
server := grpc.NewServer()
var server *grpc.Server
if config.API.APITLS {
creds := credentials.NewTLS(&tls.Config{
ClientAuth: tls.RequireAndVerifyClientCert,
Certificates: config.TLS.KeyPair,
ClientCAs: config.TLS.ClientCertPool,
})
server = grpc.NewServer(grpc.Creds(creds))
} else {
server = grpc.NewServer()
log.Warn("Using insecure API service. Please set \"api_tls\" to enable TLS-based gRPC service.")
}
service := &ServerAPI{
auth: auth,
}
Expand Down
1 change: 1 addition & 0 deletions api/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (

"github.com/p4gefau1t/trojan-go/common"
"github.com/p4gefau1t/trojan-go/conf"
_ "github.com/p4gefau1t/trojan-go/log/golog"
"github.com/p4gefau1t/trojan-go/stat/memory"
"google.golang.org/grpc"
)
Expand Down
10 changes: 7 additions & 3 deletions conf/conf.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ type TLSConfig struct {
Verify bool `json:"verify"`
CertPath string `json:"cert"`
KeyPath string `json:"key"`
ClientCertPath []string `json:"client_cert"`
KeyPassword string `json:"key_password"`
Cipher string `json:"cipher"`
CipherTLS13 string `json:"cipher_tls13"`
Expand All @@ -48,6 +49,7 @@ type TLSConfig struct {
ClientHelloID *utls.ClientHelloID
FallbackAddress *common.Address
CertPool *x509.CertPool
ClientCertPool *x509.CertPool
KeyPair []tls.Certificate
HTTPResponse []byte
CipherSuites []uint16
Expand Down Expand Up @@ -138,9 +140,11 @@ type WebsocketConfig struct {
}

type APIConfig struct {
Enabled bool `json:"enabled"`
APIHost string `json:"api_addr"`
APIPort int `json:"api_port"`
Enabled bool `json:"enabled"`
APIHost string `json:"api_addr"`
APIPort int `json:"api_port"`
APITLS bool `json:"api_tls"`
TLS TLSConfig `json:"ssl"`

APIAddress *common.Address
}
Expand Down
25 changes: 22 additions & 3 deletions conf/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,16 @@ func loadCert(tlsConfig *TLSConfig) error {
if err != nil {
return common.NewError("failed to load cert file").Base(err)
}
pool := x509.NewCertPool()
ok := pool.AppendCertsFromPEM(caCertByte)
tlsConfig.CertPool = x509.NewCertPool()
ok := tlsConfig.CertPool.AppendCertsFromPEM(caCertByte)
if !ok {
log.Warn("Invalid CA cert list")
}
log.Info("Using custom CA list")

//show info abount the cert
pemCerts := caCertByte
for len(pemCerts) > 0 {
tlsConfig.CertPool = pool
var block *pem.Block
block, pemCerts = pem.Decode(pemCerts)
if block == nil {
Expand Down Expand Up @@ -87,6 +88,19 @@ func loadCertAndKey(tlsConfig *TLSConfig) error {
}
tlsConfig.KeyPair = []tls.Certificate{keyPair}
}

tlsConfig.ClientCertPool = x509.NewCertPool()
for _, path := range tlsConfig.ClientCertPath {
log.Debug("Loading client cert: " + path)
certBytes, err := ioutil.ReadFile(path)
if err != nil {
return common.NewError("Failed to load cert file").Base(err)
}
ok := tlsConfig.ClientCertPool.AppendCertsFromPEM(certBytes)
if !ok {
return common.NewError("Invalid client cert")
}
}
return nil
}

Expand Down Expand Up @@ -139,6 +153,11 @@ func loadCommonConfig(config *GlobalConfig) error {
//api settings
if config.API.Enabled {
config.API.APIAddress = common.NewAddress(config.API.APIHost, config.API.APIPort, "tcp")
if config.API.APITLS {
if err := loadCertAndKey(&config.API.TLS); err != nil {
return err
}
}
}

//tls settings
Expand Down
15 changes: 13 additions & 2 deletions docs/content/basic/full-config.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,14 @@ weight: 30
"api": {
"enabled": false,
"api_addr": "",
"api_port": 0
"api_port": 0,
"api_tls": false,
"ssl": {
"cert": "",
"key": "",
"key_password": "",
"client_cert": []
},
}
}
```
Expand Down Expand Up @@ -320,4 +327,8 @@ trojan-go基于gRPC提供了API,以支持服务端和客户端的管理和统

```api_port```gRPC监听的端口。

警告:**不要将API直接暴露在互联网上,否则可能导致各类安全问题**
```api_tls```gRPC是否启用TLS传输(双向认证)。

```ssl``` TLS相关设置,如果开启TLS传输和双向认证,所有选项为必填。其中```key```, ```cert```为API服务器使用的密钥和证书文件,```client_cert```为客户端使用的证书文件路径,用于客户端认证。

警告:**不要将未开启TLS双向认证的API服务直接暴露在互联网上,否则可能导致各类安全问题。**
14 changes: 12 additions & 2 deletions docs/content/developer/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,18 @@ Trojan-Go基于gRPC实现了API,使用protobuf交换数据。客户端可获
```json
"api": {
"enabled": true,
"api_addr": "127.0.0.1",
"api_port": 10000
"api_addr": "0.0.0.0",
"api_port": 10000,
"api_tls": true,
"ssl": {
"cert": "api_cert.crt",
"key": "api_key.crt",
"key_password": "",
"client_cert": [
"api_client_cert1.crt",
"api_client_cert2.crt"
]
},
}
```

Expand Down

0 comments on commit 7b636d3

Please sign in to comment.