Цель нашей лабораторной получить сертификат от доверенного центра сертификации для Skype For Business 2015:
1. Выбор доверенного центра сертификации
. Let’s Encrypt
2. Выбрать способ проверки для получения сертификата
. Windows DNS Server / Yandex PDD
3. Определить список доменов в сертификате
. sfb.contoso.ru,lyncdiscoverinternal.contoso.ru,web.contoso.ru,contoso.ru
4. Получить сертификат
. ACMESharp
. DNSServer module
. Yandex API
5. Установить сертификат на сервер Skype For Business 2015
. Import-CsCertificate
. Set-CsCertificate
. Get-CsCertificate
* В сертификате от Let’s Encrypt отсутствует CRL , поэтому может возникнуть проблема с запуском сервиса Fabric и требуется исправление ключа — <Parameter Name=”CrlCheckingFlag” Value=”0”
https://itbasedtelco.wordpress.com/2016/06/14/s4b-front-end-servers-event-4097-flooding/
1. Выбор доверенного центра сертификации
Центры сертификации WoSign и StartCom, которые ранее выдавали сертификаты с большим сроком действия от 1 до 3 лет, перестали быть доверенными компанией Microsoft (https://blogs.technet.microsoft.com/mmpc/2017/08/08/microsoft-to-remove-wosign-and-startcom-certificates-in-windows-10/) и многими другими, хотя возможность получения и покупка сертификатов возможна.
К счастью, есть доверенный центр сертификации Let’s Encrypt. Его функционала будет достаточно, для создания федерации с другими партнерами и взаимодействия с сервисом Skype. Для взаимодействия с облачными сервисами, требуется дополнительное тестирование.
Let’s Encrypt:
Стоимость — бесплатно
Сертификат действителен — 90 дней
SAN — 100 доменов
CRL — не поддерживается
OCSP — поддерживается
IDN(Internationalized Domain Names) — поддерживается
OV,EV — не поддерживается
Способ проверки — ftp,http,dns
RSA размер ключа — по умолчанию 2048 (2048, 3072, 4096)
WildCard — https://letsencrypt.org/2017/07/06/wildcard-certificates-coming-jan-2018.html
Список ограничений — https://letsencrypt.org/docs/rate-limits/
Список совместимости:
https://community.letsencrypt.org/t/which-browsers-and-operating-systems-support-lets-encrypt/4394
https://letsencrypt.org/docs/certificate-compatibility/
Сроки реализации новых функций:
https://letsencrypt.org/upcoming-features/
# IDN (Internationalized Domain Names)
[System.Globalization.IdnMapping]::new().GetAscii("президент.рф")
xn--d1abbgf6aiiy.xn--p1ai
[System.Globalization.IdnMapping]::new().GetUnicode("xn--d1abbgf6aiiy.xn--p1ai")
президент.рф
2. Выбрать способ проверки для получения сертификата
В данной лабораторной работе, для простоты был выбран способ проверки через записи DNS.
Рассмотрим вариант создания записей в бесплатном сервисе Яндекс.Почта(предоставляет функционал DNS сервера) и Windows DNS Server(должен быть опубликован в интернет).
Кому лень использовать скрипты, может с легкостью получить сертификаты через онлайн сервис — https://www.sslforfree.com/
Windows DnsServer Module — https://technet.microsoft.com/en-us/itpro/powershell/windows/dnsserver/dnsserver
Get-DnsServerResourceRecord — https://technet.microsoft.com/en-us/itpro/powershell/windows/dnsserver/get-dnsserverresourcerecord
Add-DnsServerResourceRecord — https://technet.microsoft.com/en-us/itpro/powershell/windows/dnsserver/add-dnsserverresourcerecord
Set-DnsServerResourceRecord — https://technet.microsoft.com/en-us/itpro/powershell/windows/dnsserver/set-dnsserverresourcerecord
Yandex API Управление DNS — https://tech.yandex.ru/pdd/doc/concepts/api-dns-docpage/
GET /api2/admin/dns/list? — Получить DNS-записи домена — https://tech.yandex.ru/pdd/doc/reference/dns-list-docpage/
POST /api2/admin/dns/add — Добавить DNS-запись — https://tech.yandex.ru/pdd/doc/reference/dns-add-docpage/
POST /api2/admin/dns/edit — Редактировать DNS-запись — https://tech.yandex.ru/pdd/doc/reference/dns-edit-docpage/
Как подключить себе сервис Яндекса:
https://blog.it-kb.ru/2016/02/03/delegating-dns-domain-to-yandex-ns-servers-and-connect-to-free-services-yandex-mail-for-domain-with-1000-unlimited-mailboxes-and-yandex-disk/
Все DNS записи будут типа TXT, формата:
name class rr text
_acme-challenge.domain IN TXT "123drNmQL5vX0bu4YZlgy5wKNBlCny4yrjF1lSaUndc"
3. Определить список доменов в сертификате
Требования к сертифакату для Skype For Business 2015 — https://technet.microsoft.com/en-us/library/dn933910.aspx
Воспользуемся мастером и скопируем список из вкладки Subject Alternative Name — https://blogs.technet.microsoft.com/uclobby/2015/05/15/renewing-skype-for-business-server-2015-certificates/
4. Получить сертификат
К этому пункту у нас должна быть собрана информация:
+ $DomainName = "contoso.ru"
+ $SAN = "sfb.contoso.ru","lyncdiscoverinternal.contoso.ru","web.contoso.ru","contoso.ru"
+ $email = "pki@contoso.ru"
* Yandex API — учетные данные, зарегистрированный и настроенный домен
+ — Обязательные параметры
* — Необязательные параметры
! — Все действия выполняем под учетной записью с правами Администратора
Для работы с Let’s Encrypt с помощью PowerShell , есть замечательный модуль ACMESharp.
Документация по модулю — https://pkisharp.github.io/ACMESharp-docs/
User Guide: ACMESharp PowerShell Client — https://pkisharp.github.io/ACMESharp-docs/User-Guide.html
Quick Start: ACMESharp PowerShell Client — https://pkisharp.github.io/ACMESharp-docs/Quick-Start.html
ACMESharp создает Vault , которое содержит очень чувствительные данные.
* https://github.com/ebekker/ACMESharp/wiki/Vaults,-Vault-Providers-and-Vault-Profiles
:sys — the default system-wide Vault if you are running as an elevated user (admin)
%ALLUSERSPROFILE%\ACMESharp\sysVault
:user — the default user-specific Vault if you are running as a non-elevated user
%LOCALAPPDATA%\ACMESharp\userVault
Папки:
VAULT /**/ = "00-VAULT"; // Vault Info
MTADT /**/ = "01-MTADT"; // Asset Meta Data
PRVDR /**/ = "10-PRVDR"; // Challenge Handler Provider Profile
INSTP /**/ = "18-INSTP"; // Installer Provider Profile
CSRDT /**/ = "30-CSRDT"; // CSR Generation Details
KEYGN /**/ = "40-KEYGN"; // Private Key Generation Details
KEYPM /**/ = "45-KEYPM"; // Private Key PEM Export
CSRGN /**/ = "50-CSRGN"; // CSR Export
CSRPM /**/ = "55-CSRPM"; // CSR PEM Export
CSRDR /**/ = "56-CSRDR"; // CSR DER Export
CRTPM /**/ = "65-CRTPM"; // Certificate PEM Export
CRTDR /**/ = "66-CRTDR"; // Certificate DER Export
ISUPM /**/ = "75-ISUPM"; // Issuer Certificate PEM Export
ISUDR /**/ = "76-ISUDR"; // Issuer Certificate DER Export
ASSET /**/ = "99-ASSET"; // Generic Asset
Т.к. по умолчанию используется EFS для защиты Vault ,а у тех где данный функционал отключен , надо будет явно отключить в файле конфигурации EFS — https://pkisharp.github.io/ACMESharp-docs/Local-Vault-EFS.html .
public string RootPath
{ get; set; }
public bool CreatePath
{ get; set; }
public bool BypassEFS
{ get; set; }
$param = (Get-ACMEVaultProfile).VaultParameters
$param.Add("BypassEFS",$true)
Set-ACMEVaultProfile -ProfileName ":user" -Provider local -VaultParameters $param -Force
{
"$type": "ACMESharp.Vault.Profile.VaultProfile, ACMESharp.Vault",
"Name": "user",
"ProviderName": "local",
"ProviderParameters": null,
"VaultParameters": {
"$type": "System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[System.Object, mscorlib]], mscorlib",
"BypassEFS": true,
"CreatePath": true,
"RootPath": "C:\\Users\\Administrator\\AppData\\Local\\ACMESharp\\userVault"
}
}
Шаг 1: Установка модуля ACMESharp
Install-Module -Name ACMESharp -AllowClobber
Данный модуль располагается в двух репозитариях PSGallery и Nuget. Версия в PSGallery новее и на момент написания 0.9.0.321:
Install-Module -Name ACMESharp -AllowClobber -Repository PSGallery -Force
Шаг 2: Инициализация хранилища
Initialize-ACMEVault
Шаг 3: Регистрация аккаунта
* Let’s Encrypt CA поддерживает только тип email contact, URI формата mailto:<email-address>
New-ACMERegistration -Contacts mailto:$email –AcceptTos
Шаг 4: Подтверждение владением записей домена
В ACMESharp реализовано два типа ChallengeType: dns-01 , http-01 .
https-01 — описан https://pkisharp.github.io/ACMESharp-docs/Quick-Start.html
PS > Get-ACMEChallengeHandlerProfile -ListChallengeTypes
dns-01
http-01
PS > Get-ACMEChallengeHandlerProfile -ListChallengeHandlers
manual
Длинная запись:
New-ACMEIdentifier -Dns lyncdiscoverinternal.contoso.ru -Alias sfb1
New-ACMEIdentifier -Dns sfb.contoso.ru -Alias sfb2
New-ACMEIdentifier -Dns web.contoso.ru -Alias sfb3
New-ACMEIdentifier -Dns contoso.ru -Alias sfb4
Complete-ACMEChallenge -IdentifierRef sfb1 -ChallengeType dns-01 -Handler manual
Complete-ACMEChallenge -IdentifierRef sfb2 -ChallengeType dns-01 -Handler manual
Complete-ACMEChallenge -IdentifierRef sfb3 -ChallengeType dns-01 -Handler manual
Complete-ACMEChallenge -IdentifierRef sfb4 -ChallengeType dns-01 -Handler manual
Submit-ACMEChallenge -IdentifierRef sfb1 -ChallengeType dns-01
Submit-ACMEChallenge -IdentifierRef sfb2 -ChallengeType dns-01
Submit-ACMEChallenge -IdentifierRef sfb3 -ChallengeType dns-01
Submit-ACMEChallenge -IdentifierRef sfb4 -ChallengeType dns-01
## Give it a minute, just in case -- or go get more coffee
sleep -s 60
Update-ACMEIdentifier -IdentifierRef sfb1
Update-ACMEIdentifier -IdentifierRef sfb2
Update-ACMEIdentifier -IdentifierRef sfb3
Update-ACMEIdentifier -IdentifierRef sfb4
Короткая запись:
$SAN | Foreach-Object {$i=1} {
$id = "sfb$i"
New-ACMEIdentifier -Dns $_ -Alias $id | Out-Null
Complete-ACMEChallenge -IdentifierRef $id -ChallengeType dns-01 -Handler manual
$i++
}
# Содержит ресурсные записи, которые потребуется создать на DNS сервере
# Требуются для подтверждения владением доменом
$DNS = (Get-ACMEVault).Identifiers.Where{$_.Alias -like "sfb*"}.Authorization.Challenges.Where{$_.Type -eq "dns-01"}.Challenge
# Создаем ресурсные записи
# Windows DNS Server
$AllRecords = (Get-DnsServerResourceRecord -ZoneName $DomainName -RRType Txt).Where{$_.Name -match "_acme-challenge"}
$DNS.Foreach{
$rdns = $_
$name = $_.RecordName.TrimEnd($DomainName)
$record = $AllRecords.Where{$_.HostName -eq $name}
if($record)
{
$newrecord = $record.Clone()
$newrecord.RecordData.DescriptiveText = $_.RecordValue
Set-DnsServerResourceRecord -ZoneName $DomainName -NewInputObject $newrecord -OldInputObject $record
}
else
{
ADD-DnsServerResourceRecord -ZoneName $DomainName -Txt -Name $name -DescriptiveText $_.RecordValue
}
}
# Yandex API
Function Input-Captcha
{
Param($src)
Add-Type -AssemblyName System.Windows.Forms,System.Drawing
$bimg = [Net.WebClient]::new().DownloadData($src)
$ms = [IO.MemoryStream]::new($bimg)
$img = [Drawing.Image]::FromStream($ms)
[Windows.Forms.Application]::EnableVisualStyles();
$form = New-Object Windows.Forms.Form -Property @{
Text = "Captcha"
Width = 300
Height = 227
FormBorderStyle = "FixedDialog"
Icon = [Drawing.Icon]::ExtractAssociatedIcon(
"$env:ProgramFiles\Internet Explorer\iexplore.exe"
)
}
$pictureBox = New-Object Windows.Forms.PictureBox -Property @{
Width = $img.Size.Width
Height = $img.Size.Height
Location = New-Object Drawing.Size(60,30)
Image = $img
}
$button = New-Object Windows.Forms.Button -Property @{
Location = New-Object Drawing.Size(12,153)
Size = New-Object Drawing.Size(260,23)
Text = "Set"
}
$button.Add_Click({
$script:rep = $textbox.Text.Trim()
$form.Close()
})
$textbox = New-Object Windows.Forms.TextBox -Property @{
Location = New-Object Drawing.Size(12,117)
Size = New-Object Drawing.Size(260,20)
}
$form.Controls.Add($pictureBox)
$form.Controls.Add($button)
$form.Controls.Add($textbox)
$form.Add_Shown( { $form.Activate() } )
$form.ShowDialog() | Out-Null
}
Function Get-Token
{
[CmdLetBinding()]
Param(
[String]$Url = "https://pddimp.yandex.ru",
[String]$TUrl = "https://pddimp.yandex.ru/api2/admin/get_token",
[Parameter(Mandatory)]
[PSCredential]$Credential,
[Parameter(Mandatory)]
[String]$DomainName
)
try {
# Логинемся в Yandex Passport
$wr = Invoke-WebRequest $TUrl -SessionVariable ya
# В форме заполняем login&passwd
$Form = $wr.Forms[0]
$Form.Fields["login"] = $Credential.UserName
$Form.Fields["passwd"] = $Credential.GetNetworkCredential().Password
if($Form)
{
# Отправляем Post запрос
$wr = Invoke-WebRequest -Uri $Form.Action -WebSession $ya -Method POST -Body $Form
# Если успешно, то переходим к странице получения токена
$wr = Invoke-WebRequest $TUrl -WebSession $ya
if($wr.ParsedHtml.Title -eq "Admin's token management")
{
$Form = $wr.Forms[0]
# Удаляем из post запроса token_del
$Form.Fields.Remove("token_del") | Out-Null
# Вводим капчу
Input-Captcha $wr.Images.src
# Заполняем форму rep - Captcha
$Form.Fields["rep"] = $rep
$Form.Fields["domain_name"] = $DomainName
# Отправляем Post запрос с методом token_get
$wr=Invoke-WebRequest -Uri "$url$($Form.Action)" -WebSession $ya -Method POST -Body $Form
# Возвращаем полученный токен
$wr.ParsedHtml.getElementsByTagName("Strong").Item(0).outerText
}
}
}
catch {
$_
}
}
$LUrl = 'https://pddimp.yandex.ru/api2/admin/dns/list?domain={0}' -f $DomainName
$EUrl = 'https://pddimp.yandex.ru/api2/admin/dns/edit'
$AUrl = 'https://pddimp.yandex.ru/api2/admin/dns/add'
$PddToken = Get-Token -Credential "" -DomainName $DomainName
if($PddToken)
{
# Получим все записи для дальнейшего сравнения
$AllRecords = Invoke-WebRequest $LUrl -Headers @{
"accept" = "application/json"
PddToken = $PddToken
} | Foreach Content | ConvertFrom-Json | Foreach {$_.Records}
$DNS | Foreach {
$rdns = $_
$record = $AllRecords.Where{$_.FQDN -eq $rdns.RecordName}
if($record) {
# Обновляем данные
Invoke-WebRequest $EUrl -Headers @{"accept"="application/json" ; PddToken = $PddToken} -Method POST -Body @{
'domain'=$DomainName
'record_id'=$record.record_id
'content'=$rdns.RecordValue
}
}
else {
# Создаем записи
Invoke-WebRequest $AUrl -Headers @{"accept"="application/json" ; PddToken = $PddToken} -Method POST -Body @{
'domain'=$DomainName
'type'='TXT'
'subdomain' = $rdns.RecordName.TrimEnd($DomainName)
'content'=$rdns.RecordValue
}
}
}
}
Т.к. для подтверждения требуется вводить captcha вручную.
# Отправить запрос на проверку
(Get-ACMEIdentifier).Where{$_.Alias -match "sfb"}.Foreach{Submit-ACMEChallenge -IdentifierRef $_.Alias -ChallengeType dns-01}
sleep -s 60
(Get-ACMEIdentifier).Where{$_.Alias -match "sfb"}.Foreach{Update-ACMEIdentifier -IdentifierRef $_.Alias}
Шаг 5. Генерация сертификата
$idref = (Get-ACMEIdentifier).Where{$_.Alias -match "sfb"} | Select -First 1 | Foreach {$_.Alias}
$aref = (Get-ACMEIdentifier).Where{$_.Alias -match "sfb"} | Select -Skip 1 | Foreach {$_.Alias}
New-ACMECertificate -Generate -IdentifierRef $idref -AlternativeIdentifierRefs $aref -Alias SfB2015FECert
# Отправить запрос
Submit-ACMECertificate -CertificateRef SfB2015FECert
Update-ACMECertificate -CertificateRef SfB2015FECert
Шаг 6. Экспорт в PFX
Get-ACMECertificate SfB2015FECert -ExportPkcs12 "SfB2015FECert.pfx" -CertificatePassword '12345678'
5. Установить сертификат на сервер Skype For Business 2015
Пример можно посмотреть - https://www.tbs-certificates.co.uk/FAQ/en/install-skype-business-server.html
Import-CsCertificate -Path "c:\SfB2015FECert.pfx" -PrivateKeyExportable $True -Password '12345678'
Set-CsCertificate -Type Default, WebServicesInternal, WebServicesExternal,OAuthTokenIssuer -Thumbprint "439637470DF2D0E9DF933EADEA1F0610B3BA841C"
Get-CsCertificate | Ft Thumbprint,Use
Thumbprint Use
---------- ---
439637470DF2D0E9DF933EADEA1F0610B3BA841C Default
439637470DF2D0E9DF933EADEA1F0610B3BA841C WebServicesInternal
439637470DF2D0E9DF933EADEA1F0610B3BA841C WebServicesExternal
439637470DF2D0E9DF933EADEA1F0610B3BA841C OAuthTokenIssuer
PS. Скрипты к статье:
le_windows_dns.txt - Пример для Windows DNS Server
le_yandex_dns.txt — Пример использования Yandex API PDD