I'm trying to build both ARM and Bicep templates for enabling BYOK/CMK/TDE on Azure SQL server (and databases).
The challenge I'm having is that templates expect KeyVault Key Version to be passed in as an input. I'd really like to avoid that, as version could eventually change and it's not a value I'd like to maintain as an input parameter.
what I've tried so far is to create these 2 resources for SQL:
Microsoft.Sql/servers/keys#2022-05-01-preview
Microsoft.Sql/servers/encryptionProtector#2022-05-01-preview
encryptionProtector seems pretty straighforward, which just uses servers/keys resource. And that's where I'm stuck.
It requires KV key version for 'name' field, which I expected to be able to get from Microsoft.KeyVault/vaults/keys existing resource. However it only has this property:
keyVaultKey.properties.keyUriWithVersion
My next option was to parse the value, like:
var sqlServerKeyName = '${keyVaultName}_${keyVaultKeyName}_${last(split(keyVaultKey.properties.keyUriWithVersion, '/'))}'
but this results in warning:
his expression is being used in an assignment to the "name" property of the "Microsoft.Sql/servers/keys" type, which requires a value that can be calculated at the start of the deployment. You are referencing a variable which cannot be calculated at the start ("keyVaultKeyName" -> "keyVaultKey"). Properties of keyVaultKey which can be calculated at the start include "apiVersion", "id", "name", "type"
So my question is: is it possible to get KV Key Version from Bicep/ARM template and if yes - how? Or is it generally not recommended to do that (especially in the context of transparent data encryption)?
lastly, if there are no ARM/Bicep based solutions, I guess next best solution could be to try to retrieve latest version via powershell and then pass it as input. any suggestions/examples on this approach maybe?
note: KeyVault and Keys are created in separate deployment so I cannot use KV deployment output for this
The error is just about the name of the resource: the value has to be calculated when the deployment starts which is not possible in your case because the name is generated from another resource.
You would need to invoke it through another module:
// sqlserver-keyvault-encryption.bicep
param sqlServerName string
param keyVaultName string
param keyName string
param keyVersion string
param keyUri string
resource sqlServer 'Microsoft.Sql/servers#2022-05-01-preview' existing = {
name: sqlServerName
}
// Create sql server key from key vault
resource sqlServerKey 'Microsoft.Sql/servers/keys#2022-05-01-preview' = {
name: '${keyVaultName}_${keyName}_${keyVersion}'
parent: sqlServer
properties: {
serverKeyType: 'AzureKeyVault'
uri: keyUri
}
}
// Create the encryption protector
resource propector 'Microsoft.Sql/servers/encryptionProtector#2022-05-01-preview' = {
name: 'current'
parent: sqlServer
properties: {
serverKeyType: 'AzureKeyVault'
serverKeyName: sqlServerKey.name
}
}
Then you can invoke it from a parent module:
param sqlServerName string
param keyVaultName string
param keyName string
resource keyVault 'Microsoft.KeyVault/vaults#2022-07-01' existing = {
name: keyVaultName
}
resource keyVaultKey 'Microsoft.KeyVault/vaults/keys#2022-07-01' existing = {
name: keyName
parent: keyVault
}
module encryption 'sqlserver-keyvault-encryption.bicep' = {
name: 'sqlserver-keyvault-encryption'
params: {
sqlServerName: sqlServerName
keyVaultName: keyVault.name
keyName: keyVaultKey.name
keyVersion: last(split(keyVaultKey.properties.keyUriWithVersion, '/'))
keyUri: keyVaultKey.properties.keyUriWithVersion
}
}
Related
I have created a simple workbook template via Bicep without any settings.
I'd like to integrate/link it with another resource, for example application insights using Bicep and deploy it to Azure with my pipeline.
However, I do not know how I can link them together. If it is not possible, how can I link the workbook template to an App Service resource or another resource instance?
This is my workbook Bicep:
#description('The unique guid for this workbook instance.')
param workbookId string
#description('The location of the resource.')
param location string
#description('The friendly name for the workbook that is used in the Gallery or Saved List. Needs to be unique in the scope of the resource group and source.')
param workbookName string
#description('The gallery that the workbook will been shown under. Supported values include workbook, `tsg`, Azure Monitor, etc.')
param workbookType string = 'tsg'
#description('The id of resource instance to which the workbook will be associated.')
param workbookSourceId string = '<insert-your-resource-id-here>'
resource workbook 'Microsoft.Insights/workbooks#2022-04-01' = {
name: workbookId
location: location
kind: 'shared'
properties: {
displayName: workbookName
serializedData: '{"version":"Notebook/1.0","items":[{"type":1,"content":"{\\"json\\":\\"Hello World!\\"}","conditionalVisibility":null}],"isLocked":false}'
version: '1.0'
sourceId: workbookSourceId
category: workbookType
}
}
output workbookId string = workbook.id
And this is my Application Insights:
#description('Name of Application Insights resource.')
param appName string
#description('Type of app you are deploying. This field is for legacy reasons and will not impact the type of App Insights resource you deploy.')
param type string = 'web'
#description('Which Azure Region to deploy the resource to. This must be a valid Azure regionId.')
param regionId string
#description('Source of Azure Resource Manager deployment.')
param requestSource string
#description('Log Analytics workspace ID to associate with your Application Insights resource.')
param workspaceResourceId string
//param deployWorkspaceDiagnosticSettings bool = true
// #description('See documentation on tags: https://learn.microsoft.com/azure/azure-resource-manager/management/tag-resources.')
// param tagsArray object
resource applicationInsights 'Microsoft.Insights/components#2020-02-02' = {
name: appName
location: regionId
// tags: tagsArray
kind: 'other'
properties: {
Application_Type: type
Flow_Type: 'Bluefield'
Request_Source: requestSource
WorkspaceResourceId: workspaceResourceId
}
}
#description('Get Application Insights ID.')
output appIdOutput string = applicationInsights.id
#description('Get Application Type.')
output appTypeOutput string = applicationInsights.properties.Application_Type
#description('Get Instrumentation Key.')
output appInstrumentationKeyOutput string = applicationInsights.properties.InstrumentationKey
#description('The id of resource instance to which the workbook will be associated.')
param workbookSourceId string = '<insert-your-resource-id-here>'
This is what links the workbook to a resource. that workbookSourceId would be the resource id of the application insights resource, which you'd create first (if you want to link it to the app insights resource)
how you actually do that in bicep specifically i do not know, but it appears you already do similar with workspaceResourceId?
I have a logic App (a standard logic app) that make a call to cosmos DB.
I need to store the "Connection Runtime Url" under the configuration of the logic App.
When I create the connection from the logic app designer, the connection have this property. However, when I deploy the same connection using an ARM template, the connection don't have this property.
Anyone knows how can get this property or generate it? And if possible, how to call it later in an ARM template
Thanks
Only API connection of kind: 'V2' can return a connectionRuntimeUrl.
You can create a cosmos db connector with the below script (bicep):
param location string = resourceGroup().location
param cosmosDbAccountName string
param connectorName string = '${cosmosDbAccountName}-connector'
// get a reference to the cosmos db account
resource cosmosDbAccount 'Microsoft.DocumentDB/databaseAccounts#2021-06-15' existing = {
name: cosmosDbAccountName
}
// create the related connection api
resource cosmosDbConnector 'Microsoft.Web/connections#2016-06-01' = {
name: connectorName
location: location
kind: 'V2'
properties: {
displayName: connectorName
parameterValues: {
databaseAccount: cosmosDbAccount.name
accessKey: listKeys(cosmosDbAccount.id, cosmosDbAccount.apiVersion).primaryMasterKey
}
api: {
id: 'subscriptions/${subscription().subscriptionId}/providers/Microsoft.Web/locations/${location}/managedApis/documentdb'
}
}
}
output connectionRuntimeUrl string = reference(cosmosDbConnector.id, cosmosDbConnector.apiVersion, 'full').properties.connectionRuntimeUrl
The url will be an output of the generated ARM
You can then set this url as an appsetting in the workflow app:
COSMOS_CONNECTION_RUNTIMEURL: <connectionRuntimeUrl>
Then in the connections.json file, you can reference this app setting:
{
"managedApiConnections": {
"documentdb": {
...
"connectionRuntimeUrl": "#appsetting('COSMOS_CONNECTION_RUNTIMEURL')"
}
}
}
Using appsettings and parameters should make thing easier to deploy
According to this discussion, a simple API connection (V1) may not have "connectionRuntimeUrl". So, to be able to see it I need to add
"kind": "V2",
in my connection Template, also as #Thomas wrote in his answer
I'm using Pulumi 1.16 with dotnet/C# and the AzureNative stack. I try to create an EventGridTopic. To access the created resource's properties later I pull some output values.
Example code:
var topic = new Topic("eventgrid-topic-status", new TopicArgs
{
TopicName = "egt-status-dev",
ResourceGroupName = "rg-testapp-dev",
Location = "westeurope"
});
var endPointOutput = topic.Endpoint;
var endPointAccessKey = ""; // missing output property
The resource is being created. I found no way to get the access key properties:
PrimaryAccessKey
SecondaryAccessKey
In the former (elder) Azure stack the properties exist. But in Azure Native stack not. Is that on purpose, just work in progress, has been forgotten or is there some other way to retrieve these properties on this object?
This is output on Azure (old stack):
This is Azure Native, clearly the keys are missing:
I doubt that this happens accidentally and would like to understand what to do.
Azure API (and therefore Azure Native resources) return no sensitive information in their outputs automatically to minimize security risks. You have to make an explicit call to retrieve those.
In this case, you likely need to invoke the function listTopicSharedAccessKeys.
You will want to call the function from within an Apply to make sure that it's triggered only after the topic is created (e.g., not during preview):
var keys = topic.Name.Apply(topicName => ListTopicSharedAccessKeys.InvokeAsync(
new ListTopicSharedAccessKeysArgs
{
ResourceGroupName = "rg-testapp-dev",
TopicName = topicName
}));
If you don't want to hardcode the resource group name:
let keys = pulumi.all([rg.name, topic.name]).apply(arr =>
azn.eventgrid.listTopicSharedAccessKeys(
{
resourceGroupName: arr[0],
topicName: arr[1]
}
)
);
keys.apply(x => pulumi.log.info(x.key1 ?? ""));
I am trying to fetch the Azure Resource Group Deployments by using filter where name starting with "Deploy" but can't find any documentation on the $filter.
I tried to do something like below:
try
{
var credentials = new ClientSecretCredential(tenantId, clientId, clientSecret);
var resourceClient = new ResourcesManagementClient(subscriptionId, credentials);
var deployments = resourceClient.Deployments;
AsyncPageable<DeploymentExtended> rgDeployments = deployments.ListByResourceGroupAsync("myRG", "name eq 'Deploy-20210412184314'");
await foreach (DeploymentExtended deploymentProperties in rgDeployments)
{
Trace.WriteLine(deploymentProperties.Name);
}
}
catch(Exception e)
{
Trace.WriteLine(e.Message);
}
But it gives error saying -
{"error":{"code":"InvalidProvisioningStateFilter","message":"Invalid $filter 'name eq 'Deploy-20210412184314'' specified in the query string."}}
So can we only use filter like provisioningState eq '{state}' not for name?
I am using Azure Resources Management client library for .NET.
Please refer this documentation.
I am afraid you could not use the filter with name eq 'Deploy-20210412184314', in this case, if you already knew the name of the deployment and want to get it at the resource group scope, no need to use ListByResourceGroupAsync, just use this method DeploymentsOperations.GetAsync(String, String, CancellationToken), pass the resourceGroupName and deploymentName, you can simply get it.
Why Pulumi is not creating a resource group with the name I gave?
Here is my small script
const azure = require("#pulumi/azure")
const resourceGroupName = new azure.core.ResourceGroup("test-pulumi", {
location: "francecentral",
});
The name of the resource group is: test-pulumi83d54581
The name parameter that you give is your component's name, not the full name of the resource to be created. By default, Pulumi appends a suffix to all names to avoid name collision e.g. across multiple stacks.
To specify the name explicitly, pass it as options parameter:
const resourceGroupName = new azure.core.ResourceGroup("test-pulumi", {
name: "test-pulumi",
location: "francecentral",
});
That's a bit verbose, and we might get an option to disable name suffixes - see this issue for progress.