I am trying to retrieve keyVault values within my ARM template
I have enabled my keyVault for ARM template retrieval
My parameter file looks like this
"postleadrequesturl": {
"reference": {
"keyVault": {
"id": "/subscriptions/e0f18fe9-181d-4a38-90bc-f2e0101f8f05/resourceGroups/RG-DEV-SHAREDSERVICES/providers/Microsoft.KeyVault/vaults/MMSG-APIManagement"
},
"secretName": "DEV-POSTLEADREQUEST-URL"
}
}
My deploy file looks like this
{
"properties": {
"authenticationSettings": {
"subscriptionKeyRequired": false
},
"subscriptionKeyParameterNames": {
"header": "Ocp-Apim-Subscription-Key",
"query": "subscription-key"
},
"apiRevision": "1",
"isCurrent": true,
"subscriptionRequired": true,
"displayName": "MMS.CRM.PostLeadRequest",
"serviceUrl": "[parameters('postleadrequesturl')]",
"path": "CRMAPI/PostLeadRequest",
"protocols": [
"https"
]
},
"name": "[concat(variables('ApimServiceName'), '/mms-crm-postleadrequest')]",
"type": "Microsoft.ApiManagement/service/apis",
"apiVersion": "2019-01-01",
"dependsOn": []
},
The error I recieve is
Error converting value "#{keyVault=; secretName=DEV-POSTLEADREQUEST-URL}" to type 'Microsoft.WindowsAzure.ResourceStack.Frontdoor.Data.Entities.Deployments.KeyVaultParameterReference
Any thoughts?
According to my test, If we want to integrate Azure Key Vault in your Resource Manager template deployment, please refer to the following steps
Create Azure Key vault
New-AzResourceGroup -Name $resourceGroupName -Location $location
New-AzKeyVault `
-VaultName $keyVaultName `
-resourceGroupName $resourceGroupName `
-Location $location `
-EnabledForTemplateDeployment
$secretvalue = ConvertTo-SecureString 'hVFkk965BuUv' -AsPlainText -Force
$secret = Set-AzKeyVaultSecret -VaultName $keyVaultName -Name 'ExamplePassword' -SecretValue $secretvalue
$userPrincipalName = "<Email Address of the deployment operator>"
Set-AzKeyVaultAccessPolicy `
-VaultName $keyVaultName `
-UserPrincipalName $userPrincipalName `
-PermissionsToSecrets set,delete,get,list
Grant access to the key vault
The user who deploys the template must have the Microsoft.KeyVault/vaults/deploy/action permission for the scope of the resource group and key vault. The Owner and Contributor roles both grant this access.
a. Create a custom role definition JSON file
{
"Name": "Key Vault resource manager template deployment operator",
"IsCustom": true,
"Description": "Lets you deploy a resource manager template with the access to the secrets in the Key Vault.",
"Actions": [
"Microsoft.KeyVault/vaults/deploy/action"
],
"NotActions": [],
"DataActions": [],
"NotDataActions": [],
"AssignableScopes": [
"/subscriptions/00000000-0000-0000-0000-000000000000"
]
}
b. Create the new role using the JSON file:
New-AzRoleDefinition -InputFile "<PathToRoleFile>"
New-AzRoleAssignment `
-ResourceGroupName $resourceGroupName `
-RoleDefinitionName "Key Vault resource manager template deployment operator" `
-SignInName $userPrincipalName
Create ARM template
template.json
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"service_testapi068_name": {
"defaultValue": "testapi068",
"type": "String"
},
"postleadrequesturl": {
"type": "String"
}
},
"variables": {},
"resources": [
{
"type": "Microsoft.ApiManagement/service",
"apiVersion": "2019-01-01",
"name": "[parameters('service_testapi068_name')]",
"location": "Southeast Asia",
"sku": {
"name": "Developer",
"capacity": 1
},
"properties": {
"publisherEmail": "v-wenxu#microsoft.com",
"publisherName": "test",
"notificationSenderEmail": "apimgmt-noreply#mail.windowsazure.com",
"hostnameConfigurations": [
{
"type": "Proxy",
"hostName": "[concat(parameters('service_testapi068_name'), '.azure-api.net')]",
"negotiateClientCertificate": false,
"defaultSslBinding": true
}
],
"customProperties": {
"Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Protocols.Tls10": "False",
"Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Protocols.Tls11": "False",
"Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Protocols.Ssl30": "False",
"Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Ciphers.TripleDes168": "False",
"Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Backend.Protocols.Tls10": "False",
"Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Backend.Protocols.Tls11": "False",
"Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Backend.Protocols.Ssl30": "False",
"Microsoft.WindowsAzure.ApiManagement.Gateway.Protocols.Server.Http2": "False"
},
"virtualNetworkType": "None"
}
},
{
"type": "Microsoft.ApiManagement/service/apis",
"apiVersion": "2019-01-01",
"name": "[concat(parameters('service_testapi068_name'), '/demo-conference-api')]",
"dependsOn": [
"[resourceId('Microsoft.ApiManagement/service', parameters('service_testapi068_name'))]"
],
"properties": {
"displayName": "Demo Conference API",
"apiRevision": "1",
"description": "A sample API with information related to a technical conference. The available resources include *Speakers*, *Sessions* and *Topics*. A single write operation is available to provide feedback on a session.",
"serviceUrl": "[parameters('postleadrequesturl')]",
"path": "conference",
"protocols": [
"http",
"https"
],
"isCurrent": true
}
}
],
"outputs":{
"postleadrequesturl" :{
"type":"String",
"value":"[parameters('postleadrequesturl')]"
}
}
}
paramaters.json
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"postleadrequesturl": {
"reference": {
"keyVault": {
"id": "/subscriptions/e5b0fcfa-e859-43f3-8d84-5e5fe29f4c68/resourceGroups/testkeyandstorage/providers/Microsoft.KeyVault/vaults/testkey08"
},
"secretName": "postleadrequesturl"
}
}
}
}
Deploy
$name = ""
$password = ""
$secpasswd = ConvertTo-SecureString $password -AsPlainText -Force
$mycreds = New-Object System.Management.Automation.PSCredential ($name, $secpasswd)
Connect-AzAccount -Credential $mycreds
New-AzResourceGroupDeployment -ResourceGroupName "testapi06" -TemplateFile "E:\template.json" -TemplateParameterFile "E:\parameters.json"
For more details, please refer to
https://learn.microsoft.com/en-us/azure/azure-resource-manager/resource-manager-keyvault-parameter#grant-access-to-the-secrets
https://learn.microsoft.com/en-us/azure/azure-resource-manager/resource-manager-tutorial-use-key-vault
Related
I am trying to add multiple access policy in key vault for 2 object ids. One of them which belongs to same resource group as key vault and another belongs to a different resource group.
"resources": [
{
"type": "Microsoft.KeyVault/vaults",
"apiVersion": "2021-11-01-preview",
"name": "[parameters('vaultName')]",
"location": "[resourcegroup().location]",
"properties": {
"sku": {
"family": "A",
"name": "standard"
},
"tenantId": "[subscription().tenantId]",
"accessPolicies": [
{
"tenantId": "[reference(concat('Microsoft.Web/sites/', variables('functionName'), '/providers/Microsoft.ManagedIdentity/Identities/default'), '2015-08-31-PREVIEW').tenantId]",
"objectId": "[reference(concat('Microsoft.Web/sites/', variables('functionName'), '/providers/Microsoft.ManagedIdentity/Identities/default'), '2015-08-31-PREVIEW').principalId]",
"permissions": {
"secrets": [
"get",
"list"
]
}
},
{
"tenantId": "[reference(concat('Microsoft.Web/sites/', variables('functionNameAnotherRg'), '/providers/Microsoft.ManagedIdentity/Identities/default'), '2015-08-31-PREVIEW').tenantId]",
"objectId": "[reference(concat('Microsoft.Web/sites/', variables('functionNameAnotherRg'), '/providers/Microsoft.ManagedIdentity/Identities/default'), '2015-08-31-PREVIEW').principalId]",
"permissions": {
"secrets": [
"get",
"list"
]
}
}
],
"enabledForDeployment": false,
"enabledForDiskEncryption": false,
"enabledForTemplateDeployment": true,
"enableSoftDelete": true,
"softDeleteRetentionInDays": 90
}
}
]
I am getting error as application does not found in resource group. Can someone please help
Found the solution. We need to specify resource group name in order to grant access to another application belongs to another resource group.
{
"tenantId": "[reference(resourceId(parameters('AnotherResourceGroup'),'Microsoft.Web/sites', parameters('FunName')), '2021-03-01', 'Full').identity.tenantId]",
"objectId": "[reference(resourceId(parameters('AnotherResourceGroup'),'Microsoft.Web/sites', parameters('FunName')), '2021-03-01', 'Full').identity.principalId]",
"permissions": { "secrets": [ "Get", "list" ] }
}
Is there any method to add an activation date and expiration when creating secrets through arm template?
When I export the key vault template I see this:
{
"type": "Microsoft.KeyVault/vaults/secrets",
"apiVersion": "2021-11-01-preview",
"name": "[concat(parameters('vaults_we_devops_poc_kv_23_name'), '/DBConnectionStringPassword')]",
"location": "westeurope",
"dependsOn": [
"[resourceId('Microsoft.KeyVault/vaults', parameters('vaults_we_devops_poc_kv_23_name'))]"
],
"properties": {
"attributes": {
"enabled": true,
"nbf": 1648627063, - secret activation date
"exp": 2027318262 - secret expiration date
}
}
}
I think this integers are unique per secret so I can't just add these two in arm template.
I've already tried to add these two values in the arm template and nothing happens.
{
"type": "Microsoft.KeyVault/vaults/secrets",
"apiVersion": "2021-11-01-preview",
"name": "[concat(parameters('vaults_we_devops_poc_kv_23_name'), '/DBConnectionStringPassword')]",
"location": "westeurope",
"dependsOn": [
"[resourceId('Microsoft.KeyVault/vaults', parameters('vaults_we_devops_poc_kv_23_name'))]"
],
"properties": {
"attributes": {
"enabled": true
}
}
}
The integers are the times in seconds as per the docs, you can calculate their values using PowerShell:
$ActivationTime = Get-Date -Year 2022 -Month 04 -Day 15 -UFormat %s
$ExpiryTime = Get-Date -Year 2022 -Month 05 -Day 15 -UFormat %s
You can then pass those values into a template similar to this:
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"activationTime": {
"type": "int"
},
"expiryTime": {
"type": "int"
},
"secretValue": {
"type": "securestring"
}
},
"resources": [
{
"type": "Microsoft.KeyVault/vaults/secrets",
"apiVersion": "2021-10-01",
"name": "my-key-vault/test-secret",
"properties": {
"attributes": {
"enabled": true,
"exp": "[parameters('expiryTime')]",
"nbf": "[parameters('activationTime')]"
},
"value": "[parameters('secretValue')]"
}
}
]
}
Then deploy that using:
$Value = "my-secret-value"
$SecretValue = $Value | ConvertTo-SecureString -AsPlainText -Force
New-AzResourceGroupDeployment -Name TestSecretTemplate -ResourceGroupName my-resources-rg -TemplateFile .\deployment.json -activationTime $ActivationTime -expiryTime $ExpiryTime -secretValue $SecretValue
I have a function app which calls another API with a certificate. This certificate (.pfx) file is already present in the key vault. I am using below ARM template to import the certificate to SSL settings of the function app.
Note: the function app gets deployed fine when I remove section "hostNameSslStates". But after adding it, I get -
"Code": "Conflict",
"Message": "The certificate with thumbprint 'XXXXXXXX' does not match the hostname
'blobcreate-eventgridtrigger-functionapp.azurewebsites.net'."
ARM Template resources section-
`
"resources": [
//StorageAccount
{
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2019-06-01",
"name": "[parameters('storageAccounts_name')]",
"location": "[resourceGroup().location]",
"sku": {
"name": "[parameters('storageSKU')]",
"tier": "Standard"
},
"kind": "StorageV2",
"properties": {
"networkAcls": {
"bypass": "AzureServices",
"virtualNetworkRules": [],
"ipRules": [],
"defaultAction": "Allow"
},
"supportsHttpsTrafficOnly": true,
"encryption": {
"services": {
"file": {
"keyType": "Account",
"enabled": true
},
"blob": {
"keyType": "Account",
"enabled": true
}
},
"keySource": "Microsoft.Storage"
},
"accessTier": "Hot"
}
},
//BlobService
{
"type": "Microsoft.Storage/storageAccounts/blobServices",
"apiVersion": "2019-06-01",
"name": "[variables('blobServiceName')]",
"dependsOn": ["[variables('storageAccountResourceId')]"],
"sku": {
"name": "[parameters('storageSKU')]"//,
// "tier": "Standard"
},
"properties": {
"cors": {
"corsRules": []
},
"deleteRetentionPolicy": {
"enabled": false
}
}
},
//function app with server farm
//cert store access policies update-
{
"type": "Microsoft.KeyVault/vaults",
"name": "testARMTemplateKeyVault",
"apiVersion": "2016-10-01",
"location": "[resourceGroup().location]",
"properties": {
"sku": {
"family": "A",
"name": "standard"
},
"tenantId": "c29678d0-eceb-4df2-a225-79cf795a6b64",
"accessPolicies": [
{
"tenantId": "tenantIdOfSubscription", //obtained from Get-AzTenant
"objectId": "objectid of Microsoft Azure App Service", //obtained from Get-AzADServicePrincipal
"permissions": {
"keys": [
"Get",
"List",
"Update",
"Create",
"Import",
"Delete",
"Recover",
"Backup",
"Restore"
],
"secrets": [
"Get",
"List",
"Set",
"Delete",
"Recover",
"Backup",
"Restore"
],
"certificates": [
"Get",
"List",
"Update",
"Create",
"Import",
"Delete",
"Recover",
"ManageContacts",
"ManageIssuers",
"GetIssuers",
"ListIssuers",
"DeleteIssuers"
],
"storage": []
}
}
],
"enabledForDeployment": false,
"enabledForDiskEncryption": false,
"enabledForTemplateDeployment": true,
"enableSoftDelete": true
}
},
{
"type": "Microsoft.Web/serverfarms",
"apiVersion": "2018-02-01",
"name": "[variables('azurefunction_hostingPlanName')]",
"location": "[resourceGroup().location]",
"sku": {
"name": "Y1",
"tier": "Dynamic"
},
"properties": {
"name": "[variables('azurefunction_hostingPlanName')]",
"computeMode": "Dynamic"
}
},
{
"type": "Microsoft.Web/certificates",
"name": "testingcert",
"apiVersion": "2016-03-01",
"location": "[resourceGroup().location]",
"properties": {
"keyVaultId": "[resourceId('Microsoft.KeyVault/vaults', 'testARMTemplateKeyVault')]",
"keyVaultSecretName": "testingcert",
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('azurefunction_hostingPlanName'))]"
}
},
{
"apiVersion": "2018-11-01",
"type": "Microsoft.Web/sites",
"name": "[parameters('functionAppName')]",
"location": "[resourceGroup().location]",
"kind": "functionapp",
"dependsOn": [
"[variables('azureFunction_serverFarmResourceId')]",
"[variables('storageAccountResourceId')]",
"[resourceId('Microsoft.Web/certificates', 'testingcert')]"
],
"properties": {
"serverFarmId": "[variables('azureFunction_serverFarmResourceId')]",
"siteConfig": {
"appSettings": [
{
"name": "AzureWebJobsStorage",
"value": "[concat('DefaultEndpointsProtocol=https;AccountName=', parameters('storageAccounts_name'), ';AccountKey=', listKeys(variables('storageAccountResourceId'),variables('storageAccountApiVersion')).keys[0].value)]"
},
{
"name": "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING",
"value": "[concat('DefaultEndpointsProtocol=https;AccountName=', parameters('storageAccounts_name'), ';AccountKey=', listKeys(variables('storageAccountResourceId'),variables('storageAccountApiVersion')).keys[0].value)]"
},
{
"name": "WEBSITE_CONTENTSHARE",
"value": "[toLower(parameters('functionAppName'))]"
},
{
"name": "FUNCTIONS_EXTENSION_VERSION",
"value": "~2"
},
{
"name": "WEBSITE_NODE_DEFAULT_VERSION",
"value": "~10"
},
{
"name": "APPINSIGHTS_INSTRUMENTATIONKEY",
"value": "[reference(resourceId('microsoft.insights/components/', parameters('functionApp_applicationInsightsName')), '2015-05-01').InstrumentationKey]"
},
{
"name": "FUNCTIONS_WORKER_RUNTIME",
"value": "dotnet"
},
{
"name": "WEBSITE_LOAD_CERTIFICATES",
"value": "required certificate thumprint"
}
]
},
"hostNameSslStates": [
{
"name": "blobcreate-eventgridtrigger-functionapp.azurewebsites.net",//obtained from custom domains flatform features of the function app
"sslState": "SniEnabled",
"thumbprint": "[reference(resourceId('Microsoft.Web/certificates', 'testingcert')).Thumbprint]",
"toUpdate": true
}
]
}
}
]`
add certificates section in template -
{
"type": "Microsoft.Web/certificates",
"name": "[parameters('CertificateName')]",
"apiVersion": "2019-08-01",
"location": "[resourceGroup().location]",
"dependsOn": [
"[concat('Microsoft.Web/serverFarms/', variables('azurefunction_hostingPlanName'))]"
],
"properties": {
"keyVaultId": "[parameters('keyvaultResourceId')]",
"keyVaultSecretName": "[parameters('invoiceApiCertificateKeyVaultSecretName')]",
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('azurefunction_hostingPlanName'))]"
}
}
and then add dependsOn for this certificate in the function app-
[resourceId('Microsoft.Web/certificates', parameters('CertificateName'))]
well, the error is quite obvious, you are trying to add a certificate for blobcreate-eventgridtrigger-functionapp.azurewebsites.net but the dns name on the certificate doesnt match that, hence the error. that is probably not the right way to add a certificate unless its going to be used for SSL termination
I have a production keyvault that keeps a reference of secrets that projects can use, but only if deployed using ARM templates such secrets are not handled by people copy pasting them.
When a new project starts, as part of its deployment script, it will create its own keyvault.
I want to be able to run the templates/scripts as part of CI/CD. And this will today result in the same secret having a new version at each run, even though the value did not change.
How to make it only update the keyvault value when the master vault is updated.
In my deployment.sh script I use the following technique.
SendGridUriWithVersion=$((az group deployment create ... assume that the secret exists ... || az group deployment create ... assume that the secret exists ... ) | jq -r '.properties.outputs.secretUriWithVersion.value')
and it works because in the template there is a parameter, if set, that will retrieve the secret and compare it with the new value and only insert if difference. The original problem is that the deployment fails if the secret is not already set (this happens for the first deployment etc).
But then due to Unix ||, the same script is run again without the parameter set and it will use a condition to not try to get the old value and therefore run successful.
Here are the example in dept:
SecretName="Sendgrid"
SourceSecretName="Sendgrid"
SourceVaultName="io-board"
SourceResourceGroup="io-board"
SendGridUriWithVersion=$((az group deployment create -n ${SecretName}-secret -g $(prefix)-$(projectName)-$(projectEnv) --template-uri https://management.dotnetdevops.org/providers/DotNetDevOps.AzureTemplates/templates/KeyVaults/${keyVaultName}/secrets/${SecretName}?sourced=true --parameters sourceVault=${SourceVaultName} sourceResourceGroup=${SourceResourceGroup} sourceSecretName=${SourceSecretName} update=true || az group deployment create -n ${SecretName}-secret -g $(prefix)-$(projectName)-$(projectEnv) --template-uri https://management.dotnetdevops.org/providers/DotNetDevOps.AzureTemplates/templates/KeyVaults/${keyVaultName}/secrets/${SecretName}?sourced=true --parameters sourceVault=${SourceVaultName} sourceResourceGroup=${SourceResourceGroup} sourceSecretName=${SourceSecretName}) | jq -r '.properties.outputs.secretUriWithVersion.value')
The https://management.dotnetdevops.org/providers/DotNetDevOps.AzureTemplates/templates/KeyVaults/{keyvaultName}/secrets/{secretName}?sourced=true returns a template
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"keyVaultName": {
"type": "string",
"defaultValue": "io-board-data-ingest-dev"
},
"secretName": {
"type": "string",
"metadata": {
"description": "Name of the secret to store in the vault"
},
"defaultValue": "DataStorage"
},
"sourceVaultSubscription": {
"type": "string",
"defaultValue": "[subscription().subscriptionId]"
},
"sourceVault": {
"type": "string",
"defaultValue": "[subscription().subscriptionId]"
},
"sourceResourceGroup": {
"type": "string",
"defaultValue": "[resourceGroup().name]"
},
"sourceSecretName": {
"type": "string"
},
"update": {
"type": "bool",
"defaultValue": false
}
},
"variables": {
"empty": {
"value": ""
},
"test": {
"reference": {
"keyVault": {
"id": "[resourceId(subscription().subscriptionId, resourceGroup().name, 'Microsoft.KeyVault/vaults', parameters('keyVaultName'))]"
},
"secretName": "[parameters('secretName')]"
}
}
},
"resources": [
{
"apiVersion": "2018-05-01",
"name": "AddLinkedSecret",
"type": "Microsoft.Resources/deployments",
"properties": {
"mode": "Incremental",
"templateLink": {
"uri": "[concat('https://management.dotnetdevops.org/providers/DotNetDevOps.AzureTemplates/templates/KeyVaults/',parameters('keyVaultName'),'/secrets/',parameters('secretName'))]",
"contentVersion": "1.0.0.0"
},
"parameters": {
"existingValue": "[if(parameters('update'),variables('test'),variables('empty'))]",
"secretValue": {
"reference": {
"keyVault": {
"id": "[resourceId(parameters('sourceVaultSubscription'), parameters('sourceResourceGroup'), 'Microsoft.KeyVault/vaults', parameters('sourceVault'))]"
},
"secretName": "[parameters('sourceSecretName')]"
}
}
}
}
}
],
"outputs": {
"secretUriWithVersion": {
"type": "string",
"value": "[reference('AddLinkedSecret').outputs.secretUriWithVersion.value]"
}
}
}
and that template has a nested call to https://management.dotnetdevops.org/providers/DotNetDevOps.AzureTemplates/templates/KeyVaults/{keyvaultName}/secrets/{secretName} which gives the one with the condition
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"keyVaultName": {
"type": "string",
"defaultValue": "io-board-data-ingest-dev",
"metadata": {
"description": "Name of the existing vault"
}
},
"secretName": {
"type": "string",
"metadata": {
"description": "Name of the secret to store in the vault"
},
"defaultValue": "DataStorage"
},
"secretValue": {
"type": "securestring",
"metadata": {
"description": "Value of the secret to store in the vault"
}
},
"existingValue": {
"type": "securestring",
"defaultValue": ""
}
},
"variables": {},
"resources": [
{
"type": "Microsoft.KeyVault/vaults/secrets",
"condition": "[not(equals(parameters('existingValue'),parameters('secretValue')))]",
"apiVersion": "2015-06-01",
"name": "[concat(parameters('keyVaultName'), '/', parameters('secretName'))]",
"properties": {
"value": "[parameters('secretValue')]"
}
}
],
"outputs": {
"secretUriWithVersion": {
"type": "string",
"value": "[reference(resourceId(resourceGroup().name, 'Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('secretName')), '2015-06-01').secretUriWithVersion]"
}
}
}
I have a Spinnaker Pipeline with a single stage on it of type Run Job (Runs a container). This configuration has the name of the image to by ran, but the tag specifically says it will be resolved at runtime. I created a Docker Registry trigger that does indeed resolves the tag name by itself. When I Start a manual Execution, the dialog shows a dropdown for me to select the tag (this doesn't happen if the Docker Registry trigger is not setup). Until this point, both Docker Registry and Manual Execution triggers work fine.
The problem arises on the webhook trigger. I get a Status: TERMINAL with the message:
No tag found for image gcr.io/xxxx in trigger context.
I have tried passing the tag in the parameters. It doesn't work.
It happens because webhook trigger does not provide any docker artifact for your pipeline.
To solve it you may provide default artifact.
Second option is to supply an artifact description through webhook. Add you docker artifact to "Artifact Constraints " in Spinnaker:
"expectedArtifacts": [
{
"displayName": "docker-image",
"id": "artifact-id",
"matchArtifact": {
"id": "match-artifact-id",
"type": "docker/image"
},
"useDefaultArtifact": false,
"usePriorArtifact": false
}
]
...
{
"enabled": true,
"expectedArtifactIds": [
"artifact-id"
],
"payloadConstraints": {},
"source": "test",
"type": "webhook"
}
and add payload to you request:
POST http://spinnaker.cluster.local/webhooks/webhook/test
Content-Type: application/json
{
"artifacts": [
{
"name": "docker-registry.local/org/app",
"reference": "docker-registry.local/org/app:1.0.0",
"type": "docker/image",
"version": "1.0.0"
}
]
}
I also had a similar requirement for webhooks + Run Job stage, using spinnaker expressions did the trick.
Resolved it by following these steps:
Add both automated triggers - Docker registry and Webhooks
"triggers": [
{
"account": "gcr",
"enabled": true,
"expectedArtifactIds": [
"ARTIFACT_ID_PLACEHOLDER"
],
"fromTrigger": true,
"organization": "ORG_PLACEHOLDER",
"registry": "gcr.io",
"repository": "ORG_PLACEHOLDER/IMAGE_NAME_PLACEHOLDER",
"tag": "${trigger['artifacts'][0]['version']}",
"type": "docker"
},
{
"enabled": true,
"expectedArtifactIds": [
"ARTIFACT_ID_PLACEHOLDER"
],
"source": "WEBHOOK_PLACEHOLDER",
"type": "webhook"
}
]
Add expectedArtifacts
"expectedArtifacts": [
{
"defaultArtifact": {},
"displayName": "gcr.io/ORG_PLACEHOLDER/IMAGE_NAME_PLACEHOLDER",
"id": "ARTIFACT_ID_PLACEHOLDER",
"matchArtifact": {
"artifactAccount": "docker-registry",
"id": "MATCH_ARTIFACT_ID_PLACEHOLDER",
"name": "gcr.io/ORG_PLACEHOLDER/IMAGE_NAME_PLACEHOLDER",
"type": "docker/image"
},
"useDefaultArtifact": true,
"usePriorArtifact": false
}
]
Update imageDescription
"imageDescription": {
"account": "gcr",
"fromTrigger": false,
"imageId": "gcr.io/ORG_PLACEHOLDER/IMAGE_NAME_PLACEHOLDER:${trigger['artifacts'][0]['version']}",
"registry": "gcr.io",
"repository": "gcr.io/ORG_PLACEHOLDER/IMAGE_NAME_PLACEHOLDER",
"tag": "${trigger['artifacts'][0]['version']}"
}
Final JSON:
{
"appConfig": {},
"expectedArtifacts": [
{
"defaultArtifact": {},
"displayName": "gcr.io/ORG_PLACEHOLDER/IMAGE_NAME_PLACEHOLDER",
"id": "ARTIFACT_ID_PLACEHOLDER",
"matchArtifact": {
"artifactAccount": "docker-registry",
"id": "MATCH_ARTIFACT_ID_PLACEHOLDER",
"name": "gcr.io/ORG_PLACEHOLDER/IMAGE_NAME_PLACEHOLDER",
"type": "docker/image"
},
"useDefaultArtifact": true,
"usePriorArtifact": false
}
],
"keepWaitingPipelines": false,
"lastModifiedBy": "",
"limitConcurrent": true,
"spelEvaluator": "v4",
"stages": [
{
"account": "ACCOUNT_PLACEHOLDER",
"annotations": {},
"application": "APPLICATIONNAME_PLACEHOLDER",
"cloudProvider": "kubernetes",
"cloudProviderType": "kubernetes",
"containers": [
{
"args": [],
"command": [],
"envFrom": [],
"envVars": [],
"imageDescription": {
"account": "gcr",
"fromTrigger": false,
"imageId": "gcr.io/ORG_PLACEHOLDER/IMAGE_NAME_PLACEHOLDER${trigger['artifacts'][0]['version']}",
"registry": "gcr.io",
"repository": "gcr.io/ORG_PLACEHOLDER/IMAGE_NAME_PLACEHOLDER",
"tag": "${trigger['artifacts'][0]['version']}"
},
"imagePullPolicy": "ALWAYS",
"limits": {},
"name": "CONTAINER_NAME_PLACEHOLDER",
"ports": [
{
"containerPort": 80,
"name": "http",
"protocol": "TCP"
}
],
"requests": {},
"volumeMounts": []
}
],
"dnsPolicy": "ClusterFirst",
"expectedArtifacts": [
{
"defaultArtifact": {},
"displayName": "gcr.io/ORG_PLACEHOLDER/IMAGE_NAME_PLACEHOLDER",
"id": "ARTIFACT_ID_PLACEHOLDER",
"matchArtifact": {
"artifactAccount": "docker-registry",
"id": "MATCH_ARTIFACT_ID_PLACEHOLDER",
"name": "gcr.io/ORG_PLACEHOLDER/IMAGE_NAME_PLACEHOLDER",
"type": "docker/image"
},
"useDefaultArtifact": false,
"usePriorArtifact": false
}
],
"labels": {},
"name": "STAGE_NAME_PLACEHOLDER",
"namespace": "default",
"nodeSelector": {},
"refId": "1",
"requisiteStageRefIds": [],
"serviceAccountName": "",
"type": "runJob",
"volumeSources": []
}
],
"triggers": [
{
"account": "gcr",
"enabled": true,
"expectedArtifactIds": [
"ARTIFACT_ID_PLACEHOLDER"
],
"fromTrigger": true,
"organization": "ORG_PLACEHOLDER",
"registry": "gcr.io",
"repository": "ORG_PLACEHOLDER/IMAGE_NAME_PLACEHOLDER",
"tag": "${trigger['artifacts'][0]['version']}",
"type": "docker"
},
{
"enabled": true,
"expectedArtifactIds": [
"ARTIFACT_ID_PLACEHOLDER"
],
"source": "WEBHOOK_PLACEHOLDER",
"type": "webhook"
}
],
"updateTs": ""
}
Note: Replace XXXX_PLACEHOLDER such as 'ORG_PLACEHOLDER', 'IMAGE_NAME_PLACEHOLDER' etc as per your requirement in the above JSON configurations.