Защита GoCD с помощью SSL-сертификата Let’s Encrypt в Ubuntu 16.04

GoCD – это высокопроизводительная платформа непрерывной интеграции и доставки, которая автоматизирует процессы тестирования и релиз. Благодаря множеству расширенных функций (способность сравнивать сборки, визуализировать сложные рабочие процессы и автоматизировать отслеживание версий) GoCD – это гибкий инструмент, который может помочь разработчикам поставлять проверенное программное обеспечение в производственные среды.

В предыдущем руководстве вы научились устанавливать и настраивать GoCD. Этот мануал поможет настроить GoCD для поддержки SSL-сертификата от сервиса Let’s Encrypt двумя способами.

Первый метод заключается в установке Nginx в качестве обратного прокси-сервера, который будет перенаправлять соединения в конечную точку HTTP GoCD. Этот вариант, вероятно, будет лучшим в большинстве случаев.

Второй метод подразумевает получение сертификата Let’s Encrypt и отключение сертификата конечной точки HTTPS GoCD. Этот метод устраняет необходимость устанавливать отдельный веб-сервер, что может сэкономить ресурсы. Но GoCD использует хранилище SSL-сертификатов Java, которое напрямую не совместимо с форматом сертификата Let’s Encrypt. Вам понадобится создать сценарий для автоматического преобразования сертификатов в нужный формат после обновления. Этот вариант лучше подходит серверам с небольшим объемом ресурсов.

Требования

  • Сервер Ubuntu 16.04, 2 Гб RAM и 2 ядра минимум.
  • Чтобы обрабатывать артефакты сборки без искажения данных, серверу понадобится выделенный раздел или диск, который будет служить местом хранения артефактов. В данном мануале для хранения артефактов используется /mnt/artifact-storage. Настроить такой диск вам поможет руководство Разделение и форматирование дисков в Linux.
  • Пользователь с доступом к sudo и настроенный брандмауэр (вам поможет руководство по начальной настройке).
  • Домен (сервис Let’s Encrypt выдает SSL-сертификаты только по домену).

Дальнейшие требования зависят от метода, который вы хотите использовать, и будут описаны в соответствующих разделах. Выберите метод, который вы хотите использовать, и следуйте приведенным инструкциям.

Метод 1: Nginx как обратный прокси-сервер GoCD

Если вы хотите настроить Nginx как обратный прокси для GoCD, следуйте этому разделу. Веб-сервер Nginx будет настроен для поддержки трафика HTTPS с помощью сертификата Let’s Encrypt. Он будет расшифровывать клиентские соединения, а затем перенаправлять трафик на веб-интерфейс GoCD как обычный HTTP трафик. Это более простой подход.

Дополнительные требования

Установите Nginx и клиент Let’s Encrypt, а затем запросите сертификат для вашего домена. Эти руководства помогут вам:

После выполнения этих руководств платформа GoCD все равно должна быть доступна по самоподписанному сертификату (по ссылке https://your_domain:8154), а стандартная страница Nginx будет отображаться по сертификату Let’s Encrypt при удалении спецификации порта.

Настройка Nginx как обратного прокси-сервера GoCD

Итак, вы загрузили SSL-сертификат Let’s Encrypt и настроили Nginx для поддержки этого сертификата при обслуживании запросов по стандартному порту SSL. Следующий шаг – настроить Nginx для проксирования этих запросов на обычный HTTP-интерфейс GoCD, доступный по порту 8153.

Откройте виртуальный хост Nginx по умолчанию, в котором настраивалась поддержка сертификата Let’s Encrypt:

sudo nano /etc/nginx/sites-available/default

В начале файла перед блоком server откройте блок upsteam под названием gocd. В этом блоке укажите адрес, по которому Nginx может связаться с HTTP-интерфейсом GoCD. В данном случае для этого используется локальный loopback интерфейс 127.0.0.1:8153.

upstream gocd {
server 127.0.0.1:8153;
}
server {
. . .

Затем в блоке server найдите блок location/. В нем закомментируйте директиву try_files, чтобы затем указать конфигурацию прокси-сервера. Вместо строки try_files добавьте директиву proxy pass, которая включит блок upstream gocd по протоколу http://. Включите поддержку файла proxy_params, чтобы добавить в него другие параметры прокси-сервера.

. . .
server
. . .
location / {
#try_files $uri $uri/ =404;
proxy_pass http://gocd;
include proxy_params;
}
. . .

Сохраните и закройте файл.

Вернитесь в командную строку, проверьте ошибки в синтаксисе Nginx:

sudo nginx -t

Если ошибок нет, перезапустите сервис Nginx.

sudo systemctl restart nginx

Теперь пользовательский интерфейс GoCD должен быть доступен по домену и протоколу https://.

Примечание: Хотя Nginx проксирует трафик по портам 80 и 443, HTTPS-порт 8154 должен быть открытым в брандмауэре. Агенты GoCD должны иметь возможность напрямую связываться с сервером GoCD (без прокси-сервера), чтобы сервер мог проверить SSL-сертификат клиента. Открытый порт 8154 позволит внешним агентам правильно обращаться к серверу, а обычные запросы будут проходить через прокси-сервер.

Обновление URL-адреса сайта GoCD

После перезапуска Nginx остается только изменить настройки URL-адреса сайта, которые GoCD использует для создания соответствующих ссылок.

Откройте домен GoCD в браузере:

https://example.com

Нажмите ADMIN и выберите Server Configuration.

В разделе Server Management удалите из строки Site URL спецификацию порта :8154. Если вместо домена вы использовали IP-адрес, укажите в Site URL свой домен.

Нажмите SAVE в конце страницы, чтобы обновить параметры. Теперь Nginx работает как прокси-сервер GoCD.

Метод 2: Настройка GoCD для поддержки SSL-сертификата Let’s Encrypt

Этот раздел поможет настроить встроенный веб-сервер GoCD для поддержки сертификатов Let’s Encrypt. Для этого нужно заменить самоподписанный сертификат, используемый сервером GoCD, доверенным сертификатом Let’s Encrypt. Чтобы сделать это, нужно будет преобразовать файлы сертификатов в новый формат и импортировать их в файл Java keystore. Затем нужно написать сценарий, который автоматизирует процесс преобразования сертификатов при их обновлении.

Дополнительные требования

Чтобы веб-сервер GoCD самостоятельно обрабатывал все операции SSL, вам нужно будет загрузить сертификат Let’s Encrypt без процедуры настройки веб-сервера. Следуйте руководству Автоматическое извлечение SSL-сертификатов Let’s Encrypt с помощью Certbot, чтобы загрузить соответствующий клиент и получить сертификат для своего домена. Вы можете пропустить раздел по автоматическому обновлению, поскольку в этом руководстве вы научитесь создавать специальный сценарий.

После выполнения этих руководств платформа GoCD все равно должна быть доступна по самоподписанному сертификату (по ссылке https://your_domain:8154), а файлы сертификатов Let’s Encrypt должны быть в каталоге /etc/letsencrypt/live/your_domain.

Создание сценария для преобразования сертификатов

GoCD использует Java keystore для обработки сертификатов SSL. К сожалению, этот формат отличается от формата сертификатов Let’s Encrypt. Чтобы использовать сертификаты Let’s Encrypt в GoCD, нужно их преобразовать с помощью очень специфической процедуры.

Читайте также: Основы Java Keytool: работа с Java Keystore

Поскольку конвертировать сертификаты нужно во время каждого обновления, мы создадим сценарий для автоматизации процедуры. В каталоге /usr/local/bin создайте и откройте сценарий convert_certs_for_gocd.sh в текстовом редакторе:

sudo nano /usr/local/bin/convert_certs_for_gocd.sh

Вставьте в файл следующий сценарий. Единственный параметр, который вам нужно откорректировать, – это значение base_domain. Укажите в нем доменное имя сервера GoCD (это значение должно соответствовать значению в /etc/letsencrypt/live/).

#!/bin/bash
base_domain="example.com"
le_directory="/etc/letsencrypt/live/${base_domain}"
working_dir="$(mktemp -d)"
gocd_pass="serverKeystorepa55w0rd"
clean_up () {
rm -rf "${working_dir}"
}
# Use this to echo to standard error
error () {
printf "%s: %s\n" "$(basename "${BASH_SOURCE}")" "${1}" >&2
clean_up
exit 1
}
trap 'error "An unexpected error occurred."' ERR
copy_cert_files () {
cp "${le_directory}/fullchain.pem" "${working_dir}"
cp "${le_directory}/privkey.pem" "${working_dir}"
}
convert_to_pkcs12 () {
openssl_pkcs12_args=(
"pkcs12"
"-inkey" "${working_dir}/privkey.pem"
"-in" "${working_dir}/fullchain.pem"
"-export"
"-out" "${working_dir}/${base_domain}.crt.pkcs12"
"-passout" "pass:${gocd_pass}"
)
openssl "${openssl_pkcs12_args[@]}"
}
import_to_keytool () {
keytool_args=(
"-importkeystore"
"-srckeystore" "${working_dir}/${base_domain}.crt.pkcs12"
"-srcstoretype" "PKCS12"
"-srcstorepass" "${gocd_pass}"
"-destkeystore" "${working_dir}/keystore"
"-srcalias" "1"
"-destalias" "cruise"
"-deststorepass" "${gocd_pass}"
"-destkeypass" "${gocd_pass}"
)
keytool "${keytool_args[@]}"
}
install_new_keystore () {
cp /etc/go/keystore /etc/go/keystore.bak
mv "${working_dir}/keystore" "/etc/go/keystore"
chown go:go /etc/go/keystore
systemctl restart go-server
}
if (( EUID != 0 )); then
error "This script requires root privileges"
fi
copy_cert_files && convert_to_pkcs12 && import_to_keytool && install_new_keystore && clean_up

Рассмотрим этот сценарий подробнее.

В начале файла находится несколько переменных, которые упростят работу со сценарием. Они определяют домен сертификатов, которые нужно конвертировать, и путь к каталогу сертификатов Let’s Encrypt. Команда mktemp создает временный рабочий каталог и присваивает значение другой переменной. GoCD требует, чтобы все пароли Java keystore были serverKeystorepa55w0rd, это значение хранится в другой переменной.

Затем определяется функция, которая удаляет временный каталог. Она используется в конце сценария для очистки, а также при возникновении непредвиденных ошибок. Чтобы вызвать эту функцию при возникновении ошибок, нужно создать еще одну функцию, которая выводит сообщение об ошибке и выполняет чистку перед выходом. Команда trap автоматически вызовет эту функцию, когда возникнет ошибка.

Далее определяются функции, которые выполняют преобразование файлов. Первая функция подготавливает рабочее пространство, копируя закрытый ключ и сертификат в рабочий каталог. Функция convert_to_pkcs12 использует openssl, чтобы объединить файл сертификата и закрытый ключ в единый файл PKCS 12.

Для этого требуется пароль экспорта.

Следующая функция импортирует новый файл PKCS 12 в файл Java keystore и предоставляет пароль экспорта. Последняя функция копирует новый файл keystore в каталог /etc/go (после резервного копирования предыдущего файла keystore), настраивает права собственности на файл и перезапускает сервер GoCD.

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

Сохраните и закройте файл.

Преобразование сертификатов

Теперь нужно выполнить преобразование сертификатов.

Для начала сделайте сценарий исполняемым:

sudo chmod +x /usr/local/bin/convert_certs_for_gocd.sh

Вызовите сценарий с помощью sudo, чтобы преобразовать сертификаты, установить новый сгенерированный файл keystore и перезапустить GoCD.

sudo /usr/local/bin/convert_certs_for_gocd.sh

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

sudo watch netstat -plnt

На экране будут показаны TCP-порты, которые в настоящее время прослушиваются приложениями, с частотой обновления в 2 секунды. Когда GoCD начнет прослушивать порты 8153 и 8154, экран должен выглядеть так:

Every 2.0s: netstat -plnt                                                    Thu Jul 27 20:16:20 2017
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      1736/sshd
tcp6       0      0 :::22                   :::*                    LISTEN      1736/sshd
tcp6       0      0 :::8153                 :::*                    LISTEN      8942/java
tcp6       0      0 :::8154                 :::*                    LISTEN      8942/java

Чтобы остановить команду, нажмите CTRL-C.

После того, как приложение начнет прослушивать подключения, проверьте веб-интерфейс, посетив домен GoCD по порту 8154 с помощью HTTPS:

https://example.com:8154

Ранее браузер сообщал, что сертификату нельзя доверять (Not secure и красный замок в адресной строке). Кроме того, он выводил предупреждение о ненадежности сертификата:

Your connection is not private
Attackers may be trying to steal your information […]

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

Настройка автоматического обновления сертификатов

Убедившись, что сценарий правильно преобразует сертификаты, вы можете настроить certbot для использования  сценария во время обновления сертификатов.

Откройте конфигурационный файл обновления сертификатов в каталоге /etc/letsencrypt/renewal.

sudo nano /etc/letsencrypt/renewal/example.com.conf

В раздел [renewalparams] добавьте строку renew_hook, которая укажет путь к сценарию.

. . .
[renewalparams]
. . .
renew_hook = /usr/local/bin/convert_certs_for_gocd.sh

Клиент certbot устанавливает задание cron, которое два раза в день проверяет срок действия сертификатов. После обновления сертификата будет запущен сценарий, указанный в параметре renew_hook. Благодаря этой процедуре GoCD всегда будет использовать обновленные сертификаты Let’s Encrypt.

Сохраните и закройте файл.

Вы можете работу файла, запустив тестовый процесс обновления. Обратите внимание: это не приведет к запуску сценария для преобразования сертификатов; вывод сообщит, что сценарий пропущен.

sudo certbot renew --dry-run
Saving debug log to /var/log/letsencrypt/letsencrypt.log
-------------------------------------------------------------------------------
Processing /etc/letsencrypt/renewal/example.com.conf
-------------------------------------------------------------------------------
Cert not due for renewal, but simulating renewal for dry run
Renewing an existing certificate
Performing the following challenges:
http-01 challenge for example.com
Waiting for verification...
Cleaning up challenges
Dry run: skipping renewal hook command: /usr/local/bin/convert_certs_for_gocd.sh
-------------------------------------------------------------------------------
new certificate deployed without reload, fullchain is
/etc/letsencrypt/live/example.com/fullchain.pem
-------------------------------------------------------------------------------
** DRY RUN: simulating 'certbot renew' close to cert expiry
**          (The test certificates below have not been saved.)
Congratulations, all renewals succeeded. The following certs have been renewed:
/etc/letsencrypt/live/example.com/fullchain.pem (success)
** DRY RUN: simulating 'certbot renew' close to cert expiry
**          (The test certificates above have not been saved.)

Этот вывод подтверждает, что все работает должным образом.

Заключение

В этом руководстве мы рассмотрели два варианта настройки GoCD для поддержки SSL-сертификатов Let’s Encrypt. Оба метода защищают веб-интерфейс GoCD с помощью доверенного сертификата, но делают это посредством разных стратегий. Выбор наиболее подходящего метода во многом будет зависеть от требований и целей вашей команды и возможностей вашего сервера.

Tags: , , ,