Как добавить хранилище доверенных сертификатов и хранилище ключей в приложение Springboot в PCF (Pivotal Cloud Foundry)

Есть ли способ добавить хранилище доверенных сертификатов и хранилище ключей в PCF:

Приложение, развернутое в unix-боксе, может иметь хранилище доверенных сертификатов, а хранилище ключей может быть выполнено во внешнем хранилище, сохраняя их в отдельном месте и добавляя это местоположение в качестве аргументов vm.

Но как вывести хранилище ключей и трастор в PCF.

Вариант 1, с которым я столкнулся, заключается в том, чтобы хранить хранилище ключей и доверенных сертификатов внутри / в ресурсе приложения spring -boot и указывать путь в manifest.yml: аргументы JAVA_OPTS. Но что, если у нас есть 5 разных сред с 5 разными наборами хранилищ доверенных сертификатов и хранилищ ключей?

По этой причине нам необходимо экстернализировать. Подскажите, пожалуйста, есть ли способ сделать это в PCF.

Заранее спасибо !


person Avinash Jethy    schedule 19.06.2020    source источник


Ответы (1)


Как вы упомянули, есть несколько способов сделать это, и в зависимости от ваших конкретных потребностей, какой из них будет работать лучше всего. Я постараюсь обрисовать как можно больше вариантов и плюсов / минусов каждого.

  1. Если все, что вам нужно, - это распространить доверенные сертификаты, то добавление доверенных сертификатов Bosh и разрешение Bosh распространять их на все виртуальные машины и контейнеры в CF - хороший способ. В Ops Manager под плиткой Bosh перейдите в Безопасность, и вы можете добавить любое количество доверенных сертификатов.

    Это хороший подход, когда нескольким приложениям необходимо доверять сертификатам, например, в корпоративном / частном ЦС. Он также хорошо работает с разными средами / основаниями, потому что у вас есть другой Ops Manager, который может поддерживать другой список доверенных сертификатов. Это может быть сложно управлять, если у вас есть много сертификатов, которым необходимо доверять, и / или если сертификаты используются только одним или небольшим количеством приложений. Это также требует административных привилегий для CF и может занять некоторое время, чтобы развернуть обновления на всей основе.

  2. Это вариант, о котором вы упомянули в своем вопросе. Импортируйте сертификат в файл хранилища доверенных сертификатов Java, упакуйте файл в приложение Java и укажите путь к нему с помощью переменной среды JAVA_OPTS. Файл склада доверенных сертификатов можно поместить в каталог resource.

    Ex: cf set-env <app> JAVA_OPTS '-Djavax.net.ssl.trustStore=/home/vcap/app/BOOT-INF/classes/jssecacerts'

    Эта опция полезна для сценариев, не охваченных опцией № 1 выше, например, для одиночных или небольших приложений, где есть сертификаты, уникальные для этого приложения. Например, у вас есть сервер базы данных, которому вы должны доверять, и только одно приложение использует этот сервер базы данных.

    У него есть недостаток, о котором вы упомянули, хранилище доверенных сертификатов должно быть встроено в приложение, поэтому для обработки нескольких сред вам нужно будет сделать что-то вроде упаковки всех сертификатов среды в одно хранилище доверенных сертификатов и упаковать их в один JAR / WAR для всех среды или создайте несколько файлов JAR / WAR, по одному для каждой среды.

    У него также есть недостаток, заключающийся в том, что вы полностью переопределяете хранилище доверенных сертификатов по умолчанию. Хранилище доверенных сертификатов по умолчанию содержит множество хорошо известных сертификатов ЦС, поэтому вы должны начать с копии хранилища доверенных сертификатов по умолчанию и добавить сертификаты, которые вы хотите добавить. В противном случае вы потеряете список доверенных центров сертификации по умолчанию, и проверка будет нарушена для таких сайтов, как Google или Yahoo. Сертификат CA по умолчанию поставляется с каждой JRE, но может варьироваться от версии к версии, поэтому вы должны поддерживать его в актуальном состоянии.

  3. Это небольшая вариация №2. Создайте файл сценария в корневом каталоге приложения с именем .profile. В нем запустите keytool и импортируйте все сертификаты, которые упакованы с вашим приложением.

    Ex:

    #!/bin/bash 
    $HOME/.java-buildpack/open_jdk_jre/bin/keytool \
        -keystore $HOME/.java-buildpack/open_jdk_jre/lib/security/cacerts \
        -storepass changeit \
        -importcert \
        -noprompt \
        -alias MyCert \
        -file $HOME/BOOT-INF/classes/ssl/MyCert.crt
    # TODO: repeat this command for all the certs you need to import
    

    Затем запустите jar uf target/your-app.jar .profile, чтобы добавить сценарий в корень JAR / WAR вашего приложения. Сценарий должен существовать в корне вашего файла JAR / WAR, чтобы Cloud Foundry мог его подобрать и запустить. Вы можете запустить jar tf target/your-app.jar | grep profile, чтобы подтвердить это. В выводе должно быть указано .profile без ведущего пути. Если есть начальный путь, значит файл добавлен не в то место.

    Преимущество этого подхода в том, что вам не нужно предоставлять хранилище полного доверия. Это большой недостаток №2, и в этом случае вы будете аккуратно использовать хранилище доверенных сертификатов по умолчанию, упакованное с JRE, предоставляемым пакетом сборки Java. Скрипт добавит дополнительные сертификаты перед запуском вашего приложения.

    Обратной стороной этого подхода является то, что добавление сертификата беспорядочно, и его можно легко пропустить / забыть, что приведет к поломке вашего приложения. Он также должен находиться в очень конкретном месте, чтобы Cloud Foundry его обнаружила и выполнила. У этой опции также присутствует обратная сторона необходимости упаковывать ваши сертификаты в JAR / WAR.

  4. Следующий вариант - это итерация №3. В этом случае вы включаете сценарий .profile, но не упаковываете сертификаты в свой JAR / WAR. Вместо этого вы предоставляете сертификаты через переменную среды или связанную службу (это прекрасно работает с брокером служб CredHub).

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

    Ex:

    #!/bin/bash 
    $HOME/.java-buildpack/open_jdk_jre/bin/keytool \
        -keystore $HOME/.java-buildpack/open_jdk_jre/lib/security/cacerts \
        -storepass changeit \
        -importcert \
        -noprompt \
        -alias MyCert \
        -file <(echo $CERT_1)
    # TODO: repeat this command for all the certs you need to import
    

    Преимущества этого подхода такие же, как и у # 3, за исключением того, что вам больше не нужно связывать сертификаты с вашим приложением. Их можно кормить извне. Обратной стороной является тот же сценарий .profile, с которым сложно работать, и о нем можно забыть.

  5. Вариант №2 - установить системные свойства в вашем коде. Вам просто нужно, чтобы это произошло на раннем этапе запуска приложения, прежде чем JVM инициализирует TLS. Если это произойдет позже, ничего не произойдет и ваши сертификаты не будут найдены.

    В этой статье объясняется, где можно разместить код инициализации. в приложении Spring Boot. По сути, вы просто используете это для вызова System.setProperty("javax.net.ssl.trustStore", "path/to/custom/truststore"), а если вы измените пароль, System.setProperty("javax.net.ssl.trustStorePassword", "newpassword").

    Я не фанат этого подхода, потому что все может неожиданно сломаться, если TLS инициализируется до запуска вашего кода. IMHO, это сложно контролировать, особенно в Spring Boot со всеми его автоматическими конфигурациями (не то чтобы это плохо, просто вы должны быть очень осторожны с порядком). Я считаю, что это проще сделать в скрипте профиля, который гарантированно запускается до запуска вашего приложения.

  6. Другой вариант - настроить ваш WebClient вручную и вообще не зависеть от хранилища доверенных сертификатов по умолчанию. Вы можете создать свой собственный магазин доверия, что даст вам максимальную гибкость.

    Ex:

    @Bean
    public WebClient createWebClient() throws SSLException {
        SslContext sslContext = SslContextBuilder
                .forClient()
                .trustManager( /* TODO */ )
                .build();
        ClientHttpConnector httpConnector = HttpClient.create().secure(t -> t.sslContext(sslContext) )
        return WebClient.builder().clientConnector(httpConnector).build();
    }
    

    В приведенном выше коде есть маркер TODO, куда вам нужно добавить своего доверительного менеджера. В этом сообщении SO есть несколько хороших мыслей о том, как это сделать, но в целом то, что вы создаете и откуда загружаете сертификаты, довольно гибкий.

    Результатом этого метода является то, что он полностью настраивается. Вы можете получить свои сертификаты откуда угодно, из переменных среды, VCAP_SERVICES или даже из Spring Cloud Config. Они просто понадобятся вам при инициализации WebClient. Обратная сторона, вероятно, очевидна, нужно писать больше кода.


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

  1. Не получится.
  2. Он будет работать, но имеет другой аргумент JVM: javax.net.ssl.keyStore. 3 и 4. Может работать, но вместо добавления к хранилищу ключей по умолчанию вы должны создать новое в сценарии и также установить javax.net.ssl.keyStore. Это больше работы и не намного полезнее, чем №2.
  3. Он будет работать с теми же предостережениями, но имеет другой аргумент JVM: javax.net.ssl.keyStore.
  4. Он будет работать, вам просто нужно его закодировать.

Вам также нужно быть более осторожным с ключами, потому что это очень конфиденциальная информация. ИМХО, стоило бы дополнительных усилий, чтобы убедиться, что они не хранятся в JAR / WAR и хранятся в безопасности, как в CredHub или Spring Cloud Config Server.

person Daniel Mikusa    schedule 22.06.2020
comment
Примите участие в ответе на мой вопрос, это действительно помогает. - person Avinash Jethy; 22.06.2020