Сбой подтверждения подлинности для шлюза istio secure grpc

# #go #kubernetes #networking #grpc #istio

Вопрос:

Установка:

  • go сервер и клиент обмениваются данными через gRPC
  • Использование Istio для помощи в аутентификации/авторизации
  • Удалось успешно связаться с небезопасным HTTP-шлюзом
  • Теперь пытаюсь настроить безопасный шлюз HTTPS, но, похоже, это не работает. Я получаю эту ошибку на стороне клиента: "transport: authentication handshake failed: EOF"

Примечание:

  • Я следовал документам istio, чтобы настроить безопасный шлюз.
  • У меня нет домена, но я где-то читал, что это не должно быть проблемой при настройке безопасного шлюза в Istio
  • Развернут в Цифровом океане

Генерация сертификатов/ключей

 # Root certificate and private key
openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -subj '/O=test/CN=test.com' -keyout certs/test.com.key -out certs/test.com.crt

# Certificate and private key for matchmaker service
openssl req -out certs/matchmaker.test.com.csr -newkey rsa:2048 -nodes -keyout certs/matchmaker.test.com.key -subj "/CN=matchmaker.test.com/O=matchmaker" 
openssl x509 -req -days 365 -CA certs/test.com.crt -CAkey certs/test.com.key -set_serial 0 -in certs/matchmaker.test.com.csr -out certs/matchmaker.test.com.crt 
 

Проявления Кубернетеса

Создайте секрет, чтобы включить сертификат и ключ свахи:
kubectl create -n istio-system secret tls matchmaker-creds --key=path/to/matchmaker.test.com.key --cert=path/to/matchmaker.test.com.crt

Манифесты шлюза, виртуальной службы и службы:

 apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
  name: gateway
spec:
  selector:
    istio: ingressgateway # use Istio default gateway implementation
  servers:
  - port:
      number: 80
      name: grpc
      protocol: GRPC
    hosts:
      - "*"
  - port:
      number: 443
      name: https
      protocol: HTTPS
    tls:
      mode: SIMPLE
      credentialName: matchmaker-creds
    hosts:
      #- "*"
      - matchmaker.test.com
---
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: vservice
spec:
  gateways:
    - gateway
  hosts:
    #- "*"
    - matchmaker.test.com
  http:
  - match:
    - authority:
        exact: "matchmaker"
    route:
    - destination:
        host: matchmaker
        port:
          number: 5001
---
apiVersion: v1
kind: Service
metadata:
  name: matchmaker
spec:
  selector:
    server: matchmaker
  ports:
    - name: https # Note: must be changed to grpc if we're connecting through port 80 in the gateway
      port: 5001
 

Код сервера
Серверу не нужно включать какие-либо настройки для tls, так как шлюз использует завершение TLS, поэтому запрос, отправляемый в matchmaker службу, должен быть незашифрованным, верно?

 const (
    port = ":5001"
)

func main() {
    matchmakerServer, err := matchmaker.Init()
    if err != nil {
        log.Fatal(err)
    }

    lis, err := net.Listen("tcp", port)
    if err != nil {
        log.Fatalf("failed to listen: %v", err)
    }

    initializer := initializer.NewInitializer()

    grpcServer := grpc.NewServer()
    mmprotos.RegisterMatchmakerServer(grpcServer, matchmakerServer)
    initprotos.RegisterInitializerServer(grpcServer, initializer)

    // Register health check
    healthService := healthcheck.NewHealthChecker()
    grpc_health_v1.RegisterHealthServer(grpcServer, healthService)

    version := os.Getenv("VERSION")

    matchmakerServer.Logger.WithField("version", version).Infof("listening on %v", lis.Addr())

    err = grpcServer.Serve(lis)
    if err != nil {
        log.Fatalf("failed to serve: %v", err)
    }
}
 

Код клиента

 const (
    address = "<ip-addr>:443"
    token = "<jwt-token>"
)

func main() {
    creds, err := credentials.NewClientTLSFromFile("path/to/test.com.crt", "")
    if err != nil {
        log.Fatal(err)
    }

    opts := []grpc.DialOption{
        grpc.WithTransportCredentials(creds),
        grpc.WithAuthority("matchmaker"),
        //grpc.WithBlock(),
    }

    conn, err := grpc.Dial(address, opts...)
    if err != nil {
        log.Fatal(err)
    }

    defer conn.Close()

    client := initprotos.NewInitializerClient(conn)

    md := metadata.Pairs(
        "Authorization",
        fmt.Sprintf("Bearer %v", token),
    )

    ctx := metadata.NewOutgoingContext(
        context.TODO(),
        md,
    )

    _, err = client.Connect(ctx, amp;initprotos.EmptyRequest{})
    if err != nil {
        log.Fatalf("connect method err: %v", err)
    }
}
 

Журналы прокси-сервера istio не показывают ничего полезного при отправке запроса на шлюз istio.

Комментарии:

1. По-видимому, моя настройка в порядке, но проблема заключалась в добавлении SAN при подписании сертификата. Это помогло мне: security.stackexchange.com/a/159537/259808