Настройка SSL/TLS#

В данном разделе рассмотрим, как настраивать SSL/TLS на примере взаимодействия между клиентом и SOWA, а затем - между SOWA и backend.

Настройка SSL/TLS на точке входа#

  1. Необходимо сгенерировать сертификат, который будет использоваться как серверный сертификат SOWA. Для этого воспользуемся инструкцией, приведенной в разделе "Настройка и подготовка сертификатов".

  2. Создать каталог resources в examples/proxies/.

  3. Поместить туда файлы с сертификатом и ключом (SOWA_NONPRODUCTION_cert.pem и SOWA_NONPRODUCTION_cert.key).

  4. Создать конфигурационный файл профиля и сохранить его в файле proxy_ssl.yml:

    profile: proxy_ssl
    version: 2.0.3
    system:
      wrk_count: 1
      conn_count: 4096
      optional:
       log_level: error
    service:
      service_main_proxy:
       - id: main
         url: /
         listen:
          - port: 11443
            ssl:
             certificate: SOWA_NONPRODUCTION_cert.pem
             certificate_key: SOWA_NONPRODUCTION.key
         upstream_groups:
          - id: back_1
            servers:
             - server: 127.0.0.1:10012
      service_http_proxy:
       - id: 1
         name: service_1
         url:  ^/hello
         upstream_group_id: back_1
         use_main_upstream_groups: true
         allowed_queries:
           - method: get
    

    Здесь для сервиса main, который является точкой входа в секции listen, определяются параметры ssl/tls - во-первых, само наличие секции ssl означает, что на данном порту ожидается ssl подключение, параметры certificate (файл сертификата в формате PEM) и certificate_key - закрытый ключ.

  5. Добавить профиль в реестр командой add-profile.

  6. Скопировать ключ и сертификат в ресурсную папку профиля.

    Обратите внимание, что после конфигурирования данные артефакты будут удалены из каталога /sowa/profile_storage/custom/proxy_ssl.

    [sowacfg@tkle-ish0038 proxies]$ cp resources/* /sowa/profile_storage/custom/proxy_ssl/
    
  7. Сконфигурировать профиль и запустить его. Отправить запрос по протоколу https c использованием опции insecure (т.к. серверный сертификат или его подписанты не были добавлены в доверенные).

    [sowacfg@tkle-ish0038 proxies]$ curl -v https://localhost:11443/hello/world --insecure
    * About to connect() to localhost port 11443 (#0)
    *   Trying 127.0.0.1...
    * Connected to localhost (127.0.0.1) port 11443 (#0)
    * Initializing NSS with certpath: sql:/etc/pki/nssdb
    * skipping SSL peer certificate verification
    * SSL connection using TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
    * Server certificate:
    *       subject: CN=SOWA_NONPRODUCTION,OU=00CA,O=Bank of the Russian Federation,L=Moscow,ST=Moskva,C=RU
    *       start date: Apr 05 14:09:27 2021 GMT
    *       expire date: Apr 05 14:09:27 2022 GMT
    *       common name: SOWA_NONPRODUCTION
    *       issuer: CN=SOWA_NONPRODUCTION,OU=00CA,O=Bank of the Russian Federation,L=Moscow,ST=Moskva,C=RU
    

Рассмотрим теперь возможность двусторонней аутентификации - для этого в секции ssl нашего профиля пропишем опции verify_client и client_certificate.

В качестве значения опции verify_client могут быть одно из значений (on, optional, optional_no_ca) - подробнее об этом и других параметрах ssl/tls соединения рассказывается в разделе "Параметр listen".

Будет использоваться значение "on" для проверки сертификата клиента на то, что он подписан доверенным сертификатом.

В качестве доверенного, будет использоваться выпущенный нами сертификат, имя файла с которым нужно прописать в опции client_certificate. Получим следующий конфигурационный файл для нового профиля proxy_ssl_verify:

profile: proxy_ssl_verify
version: 2.0.3
system:
  wrk_count: 1
  conn_count: 4096
  optional:
   log_level: error
service:
  service_main_proxy:
   - id: main
     url: /
     listen:
      - port: 11444
        ssl:
         certificate: SOWA_NONPRODUCTION_cert.pem
         certificate_key: SOWA_NONPRODUCTION.key
         verify_client: on
         client_certificate: SOWA_NONPRODUCTION_cert.pem
     upstream_groups:
      - id: back_1
        servers:
         - server: 127.0.0.1:10012
  service_http_proxy:
   - id: 1
     name: service_1
     url:  ^/hello
     upstream_group_id: back_1
     use_main_upstream_groups: true
     allowed_queries:
       - method: get

Создадим профиль, скопируем сертификаты в ресурсную папку профиля, сконфигурируем и попробуем отправить запрос на порт 11444:

[sowacfg@tkle-ish0038 proxies]$ curl -v https://localhost:11444/hello/world --insecure
* About to connect() to localhost port 11444 (#0)
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 11444 (#0)
* Initializing NSS with certpath: sql:/etc/pki/nssdb
* skipping SSL peer certificate verification
* NSS: client certificate not found (nickname not specified)
* SSL connection using TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
* Server certificate:
*       subject: CN=SOWA_NONPRODUCTION,OU=00CA,O=Bank of the Russian Federation,L=Moscow,ST=Moskva,C=RU
*       start date: Apr 05 14:09:27 2021 GMT
*       expire date: Apr 05 14:09:27 2022 GMT
*       common name: SOWA_NONPRODUCTION
*       issuer: CN=SOWA_NONPRODUCTION,OU=00CA,O=Bank of the Russian Federation,L=Moscow,ST=Moskva,C=RU
> GET /hello/world HTTP/1.1
> User-Agent: curl/7.29.0
> Host: localhost:11444
> Accept: */*
>
< HTTP/1.1 400 Bad Request
< Date: Tue, 06 Apr 2021 11:19:22 GMT
< Content-Type: text/html
< Content-Length: 229
< Connection: close
< Server: SOWA
<
<html>
<head><title>400 No required SSL certificate was sent</title></head>
<body>
<center><h1>400 Bad Request</h1></center>
<center>No required SSL certificate was sent</center>
<hr><center>SOWA</center>
</body>
</html>
* Closing connection 0

Как видим, в этот раз ответ 200 не получен, а получена ошибка 400 - No required SSL certificate was sent.

Теперь повторим действия, но при подключении укажем сертификат, который был использован в качестве доверенного на слушателе SOWA.

[sowacfg@tkle-ish0038 proxies]$ curl -v https://localhost:11444/hello/world --insecure --cert resources/SOWA_NONPRODUCTION_cert.pem --key resources/SOWA_NONPRODUCTION.key
* About to connect() to localhost port 11444 (#0)
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 11444 (#0)
* Initializing NSS with certpath: sql:/etc/pki/nssdb
* skipping SSL peer certificate verification
* NSS: client certificate from file
*       subject: CN=SOWA_NONPRODUCTION,OU=00CA,O=Bank of the Russian Federation,L=Moscow,ST=Moskva,C=RU
*       start date: Apr 05 14:09:27 2021 GMT
*       expire date: Apr 05 14:09:27 2022 GMT
*       common name: SOWA_NONPRODUCTION
*       issuer: CN=SOWA_NONPRODUCTION,OU=00CA,O=Bank of the Russian Federation,L=Moscow,ST=Moskva,C=RU
* SSL connection using TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
* Server certificate:
*       subject: CN=SOWA_NONPRODUCTION,OU=00CA,O=Bank of the Russian Federation,L=Moscow,ST=Moskva,C=RU
*       start date: Apr 05 14:09:27 2021 GMT
*       expire date: Apr 05 14:09:27 2022 GMT
*       common name: SOWA_NONPRODUCTION
*       issuer: CN=SOWA_NONPRODUCTION,OU=00CA,O=Bank of the Russian Federation,L=Moscow,ST=Moskva,C=RU
> GET /hello/world HTTP/1.1
> User-Agent: curl/7.29.0
> Host: localhost:11444
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Tue, 06 Apr 2021 11:26:38 GMT
< Content-Type: text/html
< Content-Length: 149
< Connection: keep-alive
< Server: SOWA
<
* Connection #0 to host localhost left intact

Сгенерируем теперь клиентский сертификат, и попробуем подключиться с его помощью:

[sowacfg@tkle-ish0038 proxies]$ openssl req -newkey rsa:2048 -nodes -keyout key.pem -x509 -days 365 -out certificate.pem
Generating a 2048 bit RSA private key
..............+++
.........................+++
writing new private key to 'key.pem'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:RU
State or Province Name (full name) []:Samara
Locality Name (eg, city) [Default City]:Samara
Organization Name (eg, company) [Default Company Ltd]:Stech
Organizational Unit Name (eg, section) []:EsEn
Common Name (eg, your name or your server's hostname) []:user
Email Address []:user@user.com

Результат проверки обращения к сервису hello/world с новыми сертификатами следующий:

[sowacfg@tkle-ish0038 proxies]$ curl -v https://localhost:11444/hello/world --insecure --cert certificate.pem --key key.pem
* About to connect() to localhost port 11444 (#0)
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 11444 (#0)
* Initializing NSS with certpath: sql:/etc/pki/nssdb
* skipping SSL peer certificate verification
* NSS: client certificate from file
*       subject: E=user@user.com,CN=user,OU=EsEn,O=Stech,L=Default City,ST=Samara,C=RU
*       start date: Apr 05 14:09:27 2021 GMT
*       expire date: Apr 05 14:09:27 2022 GMT
*       common name: user
* SSL connection using TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
* Server certificate:
*       subject: CN=SOWA_NONPRODUCTION,OU=00CA,O=Bank of the Russian Federation,L=Moscow,ST=Moskva,C=RU
*       start date: Apr 05 14:09:27 2021 GMT
*       expire date: Apr 05 14:09:27 2022 GMT
*       common name: SOWA_NONPRODUCTION
*       issuer: CN=SOWA_NONPRODUCTION,OU=00CA,O=Bank of the Russian Federation,L=Moscow,ST=Moskva,C=RU
> GET /hello/world HTTP/1.1
> User-Agent: curl/7.29.0
> Host: localhost:11444
> Accept: */*
>
< HTTP/1.1 400 Bad Request
< Date: Tue, 06 Apr 2021 11:36:01 GMT
< Content-Type: text/html
< Content-Length: 229
< Connection: close
< Server: SOWA
<
<html>
<head><title>400 The SSL certificate error</title></head>
<body>
<center><h1>400 Bad Request</h1></center>

SOWA не верифицировала сертификат клиента.

Теперь создадим запрос на сертификат и подпишем его нашим доверенным сертификатом:

[sowacfg@tkle-ish0038 proxies]$ openssl genrsa -out client_signed.key 2048
Generating RSA private key, 2048 bit long modulus
......................................................................................+++
.................................................+++
e is 65537 (0x10001)
[sowacfg@tkle-ish0038 proxies]$ openssl req -new -key client_signed.key -out client_signed.cs
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:RU
State or Province Name (full name) []:Samara
Locality Name (eg, city) [Default City]:Samara
Organization Name (eg, company) [Default Company Ltd]:Stech
Organizational Unit Name (eg, section) []:EsEn.Sowa
Common Name (eg, your name or your server's hostname) []:user
Email Address []:user@user.com

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
[sowacfg@tkle-ish0038 proxies]$ openssl x509 -req -in client_signed.csr -CA resources/SOWA_NONPRODUCTION_cert.pem -CAkey resources/SOWA_NONPRODUCTION.key -CAcreateserial -out client_signed.crt -days 5000
Signature ok
subject=/C=RU/ST=Samara/L=Samara/O=Stech/OU=EsEn.Sowa/CN=user/emailAddress=user@user.com
Getting CA Private Key

И теперь, повторим запрос на сервис с новым подписанным сертификатом:

[sowacfg@tkle-ish0038 proxies]$ curl -v https://localhost:11444/hello/world --insecure --cert ./client_signed.crt --key ./client_signed.key
* About to connect() to localhost port 11444 (#0)
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 11444 (#0)
* Initializing NSS with certpath: sql:/etc/pki/nssdb
* skipping SSL peer certificate verification
* NSS: client certificate from file
*       subject: E=user@user.com,CN=user,OU=EsEn.Sowa,O=Stech,L=Samara,ST=Samara,C=RU
*       start date: Apr 06 11:48:39 2021 GMT
*       expire date: Dec 14 11:48:39 2034 GMT
*       common name: user
*       issuer: CN=SOWA_NONPRODUCTION,OU=00CA,O=Bank of the Russian Federation,L=Moscow,ST=Moskva,C=RU
* SSL connection using TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
* Server certificate:
*       subject: CN=SOWA_NONPRODUCTION,OU=00CA,O=Bank of the Russian Federation,L=Moscow,ST=Moskva,C=RU
*       start date: Apr 05 14:09:27 2021 GMT
*       expire date: Apr 05 14:09:27 2022 GMT
*       common name: SOWA_NONPRODUCTION
*       issuer: CN=SOWA_NONPRODUCTION,OU=00CA,O=Bank of the Russian Federation,L=Moscow,ST=Moskva,C=RU
> GET /hello/world HTTP/1.1
> User-Agent: curl/7.29.0
> Host: localhost:11444
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Tue, 06 Apr 2021 11:50:38 GMT
< Content-Type: text/html
< Content-Length: 149
< Connection: keep-alive
< Server: SOWA
<
* Connection #0 to host localhost left intact
Hello world[sowacfg@tkle-ish0038 proxies]$

Как видно, запрос успешно выполнен.

Настройка SSL/TLS на точке выхода - поток SOWA - backend#

Сначала добавим сервис - заглушку, которая будет принимать соединения по TLS. Для этого в файле stubs/services/plain_service.yml добавим сервис hello_world_ssl_service.

- id: hello_world_ssl_service
  optional:
    response_code: 200
    response_body: "Hello world"
  response_headers:
    - name: Content-Type
      value: text/plain
  url: ^/hello/world
  listen:
   - port: 10112
     ssl:
      certificate: SOWA_NONPRODUCTION_cert.pem
      certificate_key: SOWA_NONPRODUCTION.key

После чего скопируем сертификат и ключ в ресурсную папку профиля /sowa/profile_storage/custom/sample_stub/, переконфигурируем и перезапустим профиль.

Создадим профиль прокси-сервиса proxy_ssl_verify_upstream на основе профиля proxy_ssl_verify:

profile: proxy_ssl_verify_upstream
version: 2.0.3
system:
  wrk_count: 1
  conn_count: 4096
  optional:
   log_level: error
service:
  service_main_proxy:
   - id: main
     url: /
     listen:
      - port: 11445
        ssl:
         certificate: SOWA_NONPRODUCTION_cert.pem
         certificate_key: SOWA_NONPRODUCTION.key
         verify_client: on
         client_certificate: SOWA_NONPRODUCTION_cert.pem
     upstream_groups:
      - id: back_1
        servers:
         - server: 127.0.0.1:10112
        ssl: true
  service_http_proxy:
   - id: 1
     name: service_1
     url:  ^/hello
     upstream_group_id: back_1
     use_main_upstream_groups: true
     allowed_queries:
       - method: get

Как видно, единственное изменение, которое было сделано (кроме прописывания новых портов) — это установка значения ssl: true в настройках группы backend.

Добавим данный профиль, скопируем сертификаты в ресурсную папку профиля, сконфигурируем и запустим.

Пример обращения к профилю:

[sowacfg@tkle-ish0038 proxies]$ curl -v https://localhost:11445/hello/world --insecure --cert ./client_signed.crt --key ./client_signed.key
* About to connect() to localhost port 11445 (#0)
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 11445 (#0)
* Initializing NSS with certpath: sql:/etc/pki/nssdb
* skipping SSL peer certificate verification
* NSS: client certificate from file
*       subject: E=user@user.com,CN=user,OU=EsEn.Sowa,O=Stech,L=Samara,ST=Samara,C=RU
*       start date: Apr 06 11:48:39 2021 GMT
*       expire date: Dec 14 11:48:39 2034 GMT
*       common name: user
*       issuer: CN=SOWA_NONPRODUCTION,OU=00CA,O=Bank of the Russian Federation,L=Moscow,ST=Moskva,C=RU
* SSL connection using TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
* Server certificate:
*       subject: CN=SOWA_NONPRODUCTION,OU=00CA,O=Bank of the Russian Federation,L=Moscow,ST=Moskva,C=RU
*       start date: Apr 05 14:09:27 2021 GMT
*       expire date: Apr 05 14:09:27 2022 GMT
*       common name: SOWA_NONPRODUCTION
*       issuer: CN=SOWA_NONPRODUCTION,OU=00CA,O=Bank of the Russian Federation,L=Moscow,ST=Moskva,C=RU
> GET /hello/world HTTP/1.1
> User-Agent: curl/7.29.0
> Host: localhost:11445
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Tue, 06 Apr 2021 12:19:00 GMT
< Content-Type: text/plain
< Content-Length: 11
< Connection: keep-alive
< Server: SOWA

Запрос прошел успешно.

В случае, если необходимо включить проверку подлинности сертификата backend, то нужно определить следующие директивы для сервиса с идентификатором 1:

service_http_proxy:
  - id: 1
    name: service_1
    url:  ^/hello
    upstream_group_id: back_1
    use_main_upstream_groups: true
    allowed_queries:
      - method: get
    optional:
      proxy_ssl:
         ssl_trusted_certificate: PEM цепочка доверенных сертификатов
         ssl_verify: 'on'

Если требуется, чтобы соединение с backend устанавливалось с использованием не сертификата клиента (а другого, например, отдельного сертификата SOWA), то необходимо в этой же секции задать параметры сертификата. В данном случае сервис main_proxy отсутствует.

profile: proxy_ssl_verify_upstream
version: 2.0.3
system:
  wrk_count: 1
  conn_count: 4096
  optional:
   log_level: error
  service_http_proxy:
    - id: 1
      name: service_1
      url:  ^/hello
      upstream_group_id: back_1
      use_main_upstream_groups: true
      allowed_queries:
        - method: get
  optional:
      proxy_ssl:
        ssl_certificate: SOWA_NONPRODUCTION_cert.pem
        ssl_certificate_key: SOWA_NONPRODUCTION.key

Подобное поведение необходимо для реализации концепции SSL-Offloading.

Про остальные параметры можно прочитать в разделе "Параметр upstream_ssl".