- PVSM.RU - https://www.pvsm.ru -

Как мы зашифровали net-rpc

Мы проектировали агента для бекапов. Агент узнает у бекенда что бекапить и отправляет данные в хранилище. Злая врезка в канал и подмена адреса хранилища катастрофична.

HTTPS протестировали в первом подходе. Было ощущение, что можно сделать проще. Внутренние сервисы начинали масштабироваться по датацентрам. Хотелось сделать надежное решение для агента и внутренних сервисов. Без туннелей и HTTPS.

В итоге заменили HTTPS на net/rpc + crypto/tls.

Кроме прозрачного расширения, это дает возможность сделать свой корневой сертификат. Подписывать сертификаты сервисов и вшить проверку на клиентской стороне. Это можно сделать и в HTTPS, но удобство RPC подкупает.

Корневой сертификат.

openssl req -newkey rsa:2048 -x509 -new -keyout CA.key -days 10000 -out CA.crt

Генерируем сертификат и прошиваем DNS адрес сервиса.

openssl req -newkey rsa:2048 -nodes -keyout server.key -out server.csr
openssl x509 -req -in server.csr -CA CA.crt -CAkey CA.key -CAcreateserial -out server.pem -days 10000 -extensions v3_req -extfile backend.cnf

Конфиг OpenSSL — backend.cnf

[v3_req]
keyUsage = keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names

[alt_names]
DNS.1 = backend.rollbackup.ru

Через generate_cert.go [1] можно быстро сгенерировать сертификат без CA.

Загружаем сертификат и приватный ключ. Оборачиваем rpc в tls.Server:

import "crypto/tls"

cert, _ := tls.LoadX509KeyPair("server.pem", "server.key")
conn, _ := tls.Listen("tcp", "backend.rollbackup.ru:9001", &tls.Config{Certificates: []tls.Certificate{cert}})

server := rpc.NewServer()
for {
	if conn, err := l.Accept(); err == nil {
		go server.ServeCodec(rpc.NewServerCodec(conn))
	}
}

На клиенте фиксируем поддержку нашего корневого сертификата.

import "crypto/x509"
import "crypto/tls"
import "net/rpc"

// корневой сертификат ...
cert := `-----BEGIN CERTIFICATE----- ...`

rootCAs := x509.NewCertPool()
rootCAs.AppendCertsFromPEM([]byte(cert))

conn, _ := tls.Dial("tcp", "backend.rollbackup.ru:9001", &tls.Config{RootCAs: rootCAs})
client := rpc.NewClient(conn)

Если подменить DNS и поднять злой сервер, клиент не установит соединение.

agent connection: x509: certificate is valid for backend.rollbackup.ru, not backend.brazzers.com

Бонус трек
Усиливаем безопасность: оставляем сильные шифры и убираем поддержку TLS < 1.2. Актуально для Go 1.3.

tls.Config{
// ...
	CipherSuites: []uint16{
		tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
		tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
	},
	MinVersion: tls.VersionTLS12
})

Мы храним сертификаты на физическом токене. Чего и вам желаем.

Наша простая библиотека-обертка на Github: secrpc [2]. Примеры использования в агенте [3].

Автор: outself

Источник [4]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/shifrovanie/67421

Ссылки в тексте:

[1] generate_cert.go: http://golang.org/src/pkg/crypto/tls/generate_cert.go

[2] secrpc: https://github.com/rollbackup/secrpc

[3] в агенте: https://github.com/rollbackup/agent

[4] Источник: http://habrahabr.ru/post/232983/