Ярлыки

понедельник, 7 мая 2018 г.

Отправка Email из Azure Functions: secure way


Azure Functions - очень удобный инструмент для автоматизации каких-либо задач. Как-только автоматизация настроена - сразу возникает вопрос: как получать уведомления о результатах? Самое логичное решение - использовать электронную почту для отправки оповещений.
Как делать это безопасно и бесплатно расскажу ниже.

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

Постановка задачи


Пускай у нас уже есть:

  • Function App с именем "test-azurefunctions-notifications"
  • Учётная запись от почтового сервера (пускай будет Office 365)

Сделаем так, чтобы мы могли:

  • Отправлять уведомления из Function App
  • Не хардкодить учётку в коде Function App

Все настройки можно выполнить при помощи Azure Portal.

Настройка Function App

Открываем: Function App -> Platform features -> NETWORKING -> Managed service identity


Включаем "Register with Azure Active Directory"


Это позволить приложению запрашивать access token для получения доступа к другим ресурсам Azure (в нашем случае Key Vault). Подробнее тут.

Настройка Azure Key Vault

Создаём Key Vault по инструкции. Добавляем логин и пароль от почтового аккаунта.

Key vault -> Secrets -> Generate/Import



Разрешаем нашему Function App запрашивать эти логин и пароль. Для этого идём в Key vault -> Access policies -> Add new  и выбираем:
  • Secret permissions: Get, List
  • Select principal: test-azurefunctions-notifications


Отправка уведомлений

Проверим, что мы можем использовать сохранённые учётные данные.

Приведу вариант реализации на PowerShell. Примеры для других языков можно посмотреть в документации Microsoft.



Результат будет выглядеть примерно так:



Код на PowerShell.
#Email settings
$SendTo = "YOUR_EMAIL"
$Subj = "Hello from Azure Function"
$SMTPserver = "smtp.office365.com"
$SMTPPort = "587"
$VaultURI = "https://YOUR.vault.azure.net/"
$SenderLoginName = "YOUR-sender-ofice365-login" #How it's called in the Key Vault
$SenderPasswordName = "YOUR-sender-ofice365-password" #How it's called in the Key Vault
#Function: get Key Vault access token
function Get-AccessTokenKeyVault
{
$ResourceURI = "https://vault.azure.net"
$ApiVersion = "2017-09-01"
$TokenAuthURI = $env:MSI_ENDPOINT + "?resource=$ResourceURI&api-version=$ApiVersion"
$TokenResponse = Invoke-RestMethod -Method Get -Headers @{"Secret"="$env:MSI_SECRET"} -Uri $TokenAuthURI
$TokenResponse.access_token
}
#Function: get Key Vault secret
function Get-KeyVaultSecret
{
Param(
[string] $AccessTokenKeyVault,
[string] $SecretName
)
$ResourceURI = $VaultURI
$Uri = $ResourceURI + "secrets/$SecretName/?api-version=2016-10-01"
$keysResponse = Invoke-RestMethod -Method Get -Headers @{Authorization="Bearer $AccessTokenKeyVault"} -Uri $Uri
$keysResponse
}
function Send-Result
{
Param(
$Body
)
$Credentials = New-Object System.Management.Automation.PSCredential -ArgumentList $From, $($Password | ConvertTo-SecureString -AsPlainText -Force)
Send-MailMessage –From $From –To $SendTo –Subject $Subj –Body $Body -SmtpServer $SMTPserver -Credential $Credentials -UseSsl -Port $SMTPPort
}
#Obtain secrets
$AccessTokenKeyVault = Get-AccessTokenKeyVault
$From = (Get-KeyVaultSecret -AccessToken $AccessTokenKeyVault -SecretName $SenderLoginName).value
$Password = (Get-KeyVaultSecret -AccessToken $AccessTokenKeyVault -SecretName $SenderPasswordName).value
#Send email
Send-Result -Body "This is test from Function App at $(Get-Date)"