How to configure the TLS Inspection and IDPS in Azure Firewall Premium - azure

I want to enable the TLS Inspection and IDPS premium features of Azure Firewall Policy using the terraform. For that I have followed the articles https://learn.microsoft.com/en-us/azure/firewall/premium-certificates and https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/firewall_policy.
# Create root CA
openssl req -x509 -new -nodes -newkey rsa:4096 -keyout rootCA.key -sha256 -days 3650 -out rootCA.crt -subj '/C=US/ST=US/O=Self Signed/CN=Self Signed Root CA' -config openssl.cnf -extensions rootCA_ext
# Create intermediate CA request
openssl req -new -nodes -newkey rsa:4096 -keyout interCA.key -sha256 -out interCA.csr -subj '/C=US/ST=US/O=Self Signed/CN=Self Signed Intermediate CA'
# Sign on the intermediate CA
openssl x509 -req -in interCA.csr -CA rootCA.crt -CAkey rootCA.key -CAcreateserial -out interCA.crt -days 3650 -sha256 -extfile openssl.cnf -extensions interCA_ext
# Export the intermediate CA into PFX
openssl pkcs12 -export -out interCA.pfx -inkey interCA.key -in interCA.crt -password 'pass:'
Write-Host ""
Write-Host "================"
Write-Host "Successfully generated root and intermediate CA certificates"
Write-Host " - rootCA.crt/rootCA.key - Root CA public certificate and private key"
Write-Host " - interCA.crt/interCA.key - Intermediate CA public certificate and private key"
Write-Host " - interCA.pfx - Intermediate CA pkcs12 package which could be uploaded to Key Vault"
Write-Host "================"
and stored the interCA.pfx in the Key vault as shown below
resource "azurerm_key_vault_certificate" "example" {
name = "imported-cert"
key_vault_id = azurerm_key_vault.example.id
certificate {
contents = filebase64("interCA.pfx")
password = ""
}
}
and I have created an Azure Firewall Policy
resource "azurerm_firewall_policy" "example" {
name = "example"
resource_group_name = "example"
location = "West Europe"
identity {
type = "UserAssigned"
user_assigned_identity_ids = [azurerm_user_assigned_identity.test.id]
}
sku="Premium"
tls_certificate{
key_vault_secret_id = azurerm_key_vault_secret.example.id
name = "imported-cert"
}
intrusion_detection {
mode="Alert"
signature_overrides {
id = "sigOverrideParam1 id (2024897)"
state = "Deny"
}
signature_overrides {
id = "sigOverrideParam2 id (2024898)"
state = "Alert"
}
traffic_bypass {
name = "SecretBypass"
protocol ="TCP"
source_addresses = ["*"]
destination_addresses =["1.1.1.1"]
destination_ports = ["80"]
}
}
}
am I missing something?

I think you will also need to set a keyvault access policy in your terraform to allow the managed identity to get the secret/certificate from your keyvault. See the keyvault access policy documentation for more details.

Related

Why I'm I getting a 403 using Azure Service Management API?

I want to use the Azure API Management (management.core.windows.net) to reboot role instance (ref to Microsoft documentation: https://learn.microsoft.com/en-us/rest/api/compute/cloudservices/rest-reboot-role-instance) but I'm getting a 403 as a response.
Request:
https://management.core.windows.net/{subscription-id}/services/hostedservices/{hosted-service}/deploymentslots/staging/roleinstances/{role-instance-name}?comp=reboot`
Headers:
- Authorization: Bearer {token}
- Content-Type: application/xml
- x-ms-version: 2010-10-28
- Content-Length: 0
Body: Empty
Response Body:
<Error xmlns="http://schemas.microsoft.com/windowsazure" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Code>ForbiddenError</Code>
<Message>The server failed to authenticate the request. Verify that the certificate is valid and is associated with this subscription.</Message>
</Error>
I get the Authentication - Bearer Token by calling (ref to Microsoft documentation: https://learn.microsoft.com/en-us/azure/active-directory/azuread-dev/v1-oauth2-client-creds-grant-flow#service-to-service-access-token-request):
https://login.microsoftonline.com/{tenant_id}/oauth2/token
Headers:
- Content-Type: application/x-www-form-urlencoded
Body:
- grant_type: client_credentials,
- client_id: {client_id}
- client_secret: {client_secret}
- resource: https://management.core.windows.net/
Any idea? Any missing configuration on the request or Azure Portal side? Is the management.core.windows.net deprecated since I can use the management.azure.com?
Notes:
I already configured the permissions on the Azure side: I created an app registration for this, with a secret used to give permissions as contributor;
The management.azure.com API works with the Bearer Token. I can access other resources such as https://management.azure.com/subscriptions/{subscription-id}/resourcegroups?api-version=2017-05-10 but I can't access the https://management.core.windows.net/{subscription-id}/services/hostedservices resources.
I'm testing this on Postman.
SOLUTION
The problem was related to the certificate configuration
$cert = New-SelfSignedCertificate -Subject "CN=Azure Management API" -CertStoreLocation "cert:\LocalMachine\My" -KeyLength 2048 -KeySpec "KeyExchange" -NotAfter (Get-Date).AddMonths(360)
$password = ConvertTo-SecureString -String "strong-password-here" -Force -AsPlainText
Export-PfxCertificate -Cert $cert -FilePath ".\azure-management-api.pfx" -Password $password
Export-Certificate -Type CERT -Cert $cert -FilePath .\azure-management-api.cer
Attention to the importance of the certificate to be a .pfx
CODE
var cert = new X509Certificate2( File.ReadAllBytes( "your-certificate-path.pfx" ), "your_password" );
var httpClientHandler = new HttpClientHandler
{
UseProxy = false,
ClientCertificateOptions = ClientCertificateOption.Manual
};
httpClientHandler.ClientCertificates.Add( cert );
var httpClient = new HttpClient( httpClientHandler );
httpClient.DefaultRequestHeaders.Add( "Accept", "application/xml" );
httpClient.DefaultRequestHeaders.Add( "Host", "management.core.windows.net" );
httpClient.DefaultRequestHeaders.Add( "x-ms-version", "2010-10-28" );
var uri = $"https://management.core.windows.net/{subscriptionId}/services/hostedservices";
Console.WriteLine( $"GET {uri} [{httpClient.DefaultRequestVersion}]" );
foreach ( var header in httpClient.DefaultRequestHeaders )
{
Console.WriteLine( $"{header.Key} {header.Value.First()}" );
}
var response = httpClient.GetAsync( uri )
.GetAwaiter()
.GetResult();
var content = response.Content.ReadAsStringAsync()
.GetAwaiter()
.GetResult();
Console.WriteLine( $"{(int)response.StatusCode} {response.StatusCode}" );
Console.WriteLine( content );
httpClient.Dispose();
httpClientHandler.Dispose();
According to your description, you want to manage Azure cloud service. Azure cloud service is Azure classic resource. So we need to use Azure service management API to manage it. If we want to call the API, we need to do X509 client certificates authentication. For more details, please refer to the document
The detailed steps are as below
Upload certificate to Azure
a. create a certificate
$cert = New-SelfSignedCertificate -DnsName yourdomain.cloudapp.net -CertStoreLocation "cert:\LocalMachine\My" -KeyLength 2048 -KeySpec "KeyExchange"
$password = ConvertTo-SecureString -String "your-password" -Force -AsPlainText
Export-PfxCertificate -Cert $cert -FilePath ".\my-cert-file.pfx" -Password $password
Export-Certificate -Type CERT -Cert $cert -FilePath .\my-cert-file.cer
b upload .cer file to Azure(Subscriptions -> your subscription -> Management certificates)
Code (for example, I list cloud service in my subscription )
static async Task Main(string[] args)
{
var _clientHandler = new HttpClientHandler();
_clientHandler.ClientCertificates.Add(GetStoreCertificate("the cert's thumbprint" ));
_clientHandler.ClientCertificateOptions = ClientCertificateOption.Manual;
String uri = string.Format("https://management.core.windows.net/{0}/services/hostedservices", "subscription id");
using (var _client = new HttpClient(_clientHandler))
using (var request = new HttpRequestMessage(HttpMethod.Get, uri)) {
request.Headers.Add("x-ms-version", "2014-05-01");
request.Headers.Add("Accept", "application/xml");
//request.Headers.Add("Content-Type", "application/xml");
using (HttpResponseMessage httpResponseMessage = await _client.SendAsync(request)) {
string xmlString = await httpResponseMessage.Content.ReadAsStringAsync();
Console.WriteLine(httpResponseMessage.StatusCode);
Console.WriteLine(xmlString);
}
}
}
private static X509Certificate2 GetStoreCertificate(string thumbprint)
{
X509Store store = new X509Store("My", StoreLocation.LocalMachine);
try
{
store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
X509Certificate2Collection certificates = store.Certificates.Find(
X509FindType.FindByThumbprint, thumbprint, false);
if (certificates.Count == 1)
{
return certificates[0];
}
}
finally
{
store.Close();
}
throw new ArgumentException(string.Format(
"A Certificate with Thumbprint '{0}' could not be located.",
thumbprint));
}

How can I sign a JWT to exchange an access token from azure active directory?

I am coding by nodejs and I am referring to this doc :
https://learn.microsoft.com/en-us/azure/active-directory/develop/v1-oauth2-client-creds-grant-flow#second-case-access-token-request-with-a-certificate
As this doc said , I can get an access token by a JWT token . This doc indicated how to sign a JWT :
https://learn.microsoft.com/en-us/azure/active-directory/develop/active-directory-certificate-credentials
but I can't find any demo code about it.So how can I implement it to get an access token to call microsoft graph apis by nodejs ?
Any assistance is appreciated, thanks !
To go through this whole process , we should create certs first. I use self-signed certs for demo here .
Step 1 : Create .cer and .key files, we will upload .cer to Azure AD App and use .key file to sign our JWT tokens.
1) Create a self signed cert which password is 123456 by Powershell :
$cert = New-SelfSignedCertificate -certstorelocation cert:\localmachine\my -dnsname stantest.com
$pwd = ConvertTo-SecureString -String '123456' -Force -AsPlainText
$path = 'cert:\localMachine\my\' + $cert.thumbprint
Export-PfxCertificate -cert $path -FilePath <path of your pfx file> -Password $pwd
2) Create .cer file based on .pfx file in CMD:
openssl pkcs12 -in <path of .pfx file> -clcerts -nokeys -out <path of .cer>
3) Create .key file based on .pfx file in CMD:
openssl pkcs12 -in <path of .pfx file> -nocerts -nodes -out <path of .pem file>
openssl rsa -in <path of .pem file> -out <path of .key file>
Finally , we will get files below :
STEP 2 : Upload .cer file to your Azure AD app and note its Thumbprint value:
STEP 3 : Use the nodejs code below to sign a JWT and exchange an access token for Microsoft Graph APIs :
var jwt = require("jsonwebtoken");
var fs = require("fs");
var uuidv1 = require('uuid/v1');
var fetch = require("node-fetch");
var tenant = "<your tenant ID/Name>";
var clientID = "<your Azure AD app ID>";
var certThumbprint = "<.cer Thumbprint value on Azure portal>";
var privateKey = fs.readFileSync("<path of your .key file>").toString();
var certOctets = certThumbprint.match(/.{1,2}/g)
var certBuffer = Buffer.alloc(certOctets.length)
for(var i=0; i<certOctets.length; i++){
certBuffer.writeUInt8(parseInt(certOctets[i], 16), i);
}
//Perform base64url-encoding as per RFC7515 Appendix C
var x5t = certBuffer.toString('base64').replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_');
var current = Date.now().toString().substr(0,10);
var payload=
{
"aud":"https://login.microsoftonline.com/"+tenant+"/oauth2/token",
"exp": Number(current) + 3600,
"iss":clientID,
"jti":uuidv1(),
"nbf":Number(current),
"sub":clientID
}
var token = jwt.sign(payload,privateKey,{algorithm: 'RS256',header: {"x5t": x5t}})
var reqTokenBody =
"grant_type=client_credentials&"+
"client_id="+clientID + "&" +
"resource=https://graph.microsoft.com&"+
"client_assertion="+ token +"&" +
"client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer"
fetch("https://login.microsoftonline.com/hanxia.onmicrosoft.com/oauth2/token",
{
method: 'POST',
headers:
{
'Content-Type': 'application/x-www-form-urlencoded',
},
body:reqTokenBody,
}).then((response) => response.json()).then((data) =>
{
console.log(JSON.stringify(data, null, 2));
}).catch((error) =>
{
console.log(error);
});
Result :
Hope it helps.

How to copy a certificate from one Azure Key Vault to another?

I am trying to copy a certificate from one key vault into another without persisting it on local machine. I looks like Azure KeyVault CLI only supports file-based certificate import like this:
# download cert
az keyvault certificate download --file $certFileName --vault-name $sourceAkv -n $certName
# import cert
az keyvault certificate import --file $certFileName --vault-name $destAkv -n $certName
Is there any way to pass an object or string instead? In Azure Powershell module this is possible:
Import-AzureKeyVaultCertificate -VaultName $DestinationVaultName -Name $CertificateName -CertificateString $secretText.SecretValueText
Thoughts?
I found something like this can work in PowerShell to export the certificate and key as an object, then import it into another keyvault without having to save it as a temporary PFX file.
$CertName = 'mycert'
$SrcVault = 'mysourcekeyvault'
$DstVault = 'mydestinationkeyvault'
$cert = Get-AzKeyVaultCertificate -VaultName $SrcVault -Name $CertName
$secret = Get-AzKeyVaultSecret -VaultName $SrcVault -Name $cert.Name
$secretValueText = '';
$ssPtr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($secret.SecretValue)
try {
$secretValueText = [System.Runtime.InteropServices.Marshal]::PtrToStringBSTR($ssPtr)
}
finally {
[System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($ssPtr)
}
$secretByte = [Convert]::FromBase64String($secretValueText)
$x509Cert = new-object System.Security.Cryptography.X509Certificates.X509Certificate2
$x509Cert.Import($secretByte, "", "Exportable,PersistKeySet")
Import-AzKeyVaultCertificate -VaultName $DstVault -Name $CertName -CertificateCollection $x509Cert
It seems that there is no way to just import the certificate context to the Azure Keyvault as you say. It only has the parameter dependant on the certificate file.

Deploying azure automation account cert

I generated a pfx blob using this script :
$appId = Read-Host "Enter application ID of service principal"
$adApp = (Get-AzureRmADApplication -ApplicationId $appId)[0]
$spnId = (Get-AzureRmADServicePrincipal -ServicePrincipalName $adApp.IdentifierUris[0])[0].Id.Guid
$endDate = (Get-Date).AddYears(1)
$certSelfSigned = New-SelfSignedCertificateEx -Subject "CN=$spnId" -StoreLocation CurrentUser -NotAfter $endDate -Exportable -Provider "Microsoft Enhanced RSA and AES Cryptographic Provider"
$publicKey = [System.Convert]::ToBase64String($certSelfSigned.GetRawCertData())
New-AzureRmADSpCredential -ServicePrincipalObjectId $spnId -CertValue $publicKey -EndDate $certSelfSigned.GetExpirationDateString()
# TEST: Login-AzureRmAccount -ServicePrincipal -CertificateThumbprint $certSelfSigned.Thumbprint -ApplicationId $appId -TenantId <guid>
$storeLocation = [Security.Cryptography.X509Certificates.StoreLocation]::CurrentUser
$storeName = [Security.Cryptography.X509Certificates.StoreName]::My
$store = New-Object -TypeName System.Security.Cryptography.X509Certificates.X509Store #($storeName, $storeLocation)
$store.Open([Security.Cryptography.X509Certificates.OpenFlags]::OpenExistingOnly)
$findType = [System.Security.Cryptography.X509Certificates.X509FindType]::FindByThumbprint
$cert = $store.Certificates.Find($findType, $certSelfSigned.Thumbprint, $false)
$pfxBlob = [System.Convert]::ToBase64String($cert.Export([Security.Cryptography.X509Certificates.X509ContentType]::Pkcs12))
$store.Close()
"THUMBPRINT: $($certSelfSigned.Thumbprint)"
"PFX BLOB: `n$pfxBlob"
I copied the pfx blob and made a .pfx file and in azure portal when I create a new certificate for an automation account and upload the file I created before it gives me internal server error.
What is the correct format of .pfx file and what is the password that I will be using to set and how will I use a thumbprint?

Azure Add-AzureProvisioningConfig ssh key or key pair upload

Using Azure Powershell commandlets, I want to provision a new Linux VM with no SSH password and only SSH keys (necessary when provisioning CoreOS). When using the Azure CLI along with a public key file specified on the command line, everything works well. Apparently this is not available for the Powershell commandlet Add-AzureProvisioningConfig. It takes two possible SSH Key arguments, but they are both lists of key pairs. As documented here, the argument -SSHKeyPairs specifies a list of SSH key pairs already deployed in the subscription. I have no idea how to deploy key pairs in the subscription, nor can I find it documented anywhere. Likewise, -SSHPublicKeys specifies a list of SSH public keys already deployed in the subscription.
You can use Openssl.exe utility to generate the certificate.
Here is an example of what this command :
openssl.exe req -x509 -nodes -days 365 -newkey rsa:2048 -keyout myPrivateKey.key -out myCert.pem
Complete example of how to provision a Linux virtual machine using an SSH:
$location = "West US"
$serviceName = "contosolinux1"
$vmName = "linuxvm1"
$size = "Small"
$adminUser = "[admin user name]"
$password = "[admin password]"
$imageFamily = "Ubuntu Server 14.10 DAILY"
$imageName = Get-AzureVMImage |
where { $_.ImageFamily -eq $imageFamily } |
sort PublishedDate -Descending |
select -ExpandProperty ImageName -First 1
$certPath = "$PSScriptRoot\MyCert.pem"
New-AzureService -ServiceName $serviceName `
-Location $location
$cert = Get-PfxCertificate -FilePath $certPath
Add-AzureCertificate -CertToDeploy $certPath `
-ServiceName $serviceName
$sshKey = New-AzureSSHKey -PublicKey -Fingerprint $cert.Thumbprint `
-Path "/home/$linuxUser/.ssh/authorized_keys"
New-AzureVMConfig -Name $vmName `
-InstanceSize $size `
-ImageName $imageName |
Add-AzureProvisioningConfig -Linux `
-AdminUsername $adminUser `
-Password $password `
-SSHPublicKeys $sshKey |
New-AzureVM -ServiceName $serviceName
Source : https://www.microsoftpressstore.com/store/exam-ref-70-533-implementing-microsoft-azure-infrastructure-9780735697065

Resources