Как мы зашифровали 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 можно быстро сгенерировать сертификат без 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. Примеры использования в агенте.

© Habrahabr.ru