Skip to content

Commit 578318c

Browse files
authored
Merge pull request #71 from Keyfactor/create_vault_bugfix_ab#78506
Bugfix for error when creating a new Azure Keyvault
2 parents acf5ea6 + f463305 commit 578318c

21 files changed

+150
-39
lines changed

.github/dependabot.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# See GitHub's documentation for more information on this file:
2+
# https://docs.github.com/en/code-security/supply-chain-security/keeping-your-dependencies-updated-automatically/configuration-options-for-dependency-updates
3+
version: 2
4+
updates:
5+
- package-ecosystem: "github-actions"
6+
directory: "/"
7+
schedule:
8+
interval: "daily"
9+
- package-ecosystem: "nuget"
10+
directory: "/"
11+
schedule:
12+
interval: "daily"

.github/workflows/keyfactor-release-workflow.yml

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: Keyfactor Release Workflow
1+
name: Keyfactor Bootstrap Workflow
22

33
on:
44
workflow_dispatch:
@@ -11,10 +11,17 @@ on:
1111

1212
jobs:
1313
call-starter-workflow:
14-
uses: keyfactor/actions/.github/workflows/starter.yml@v3.1.2
14+
uses: keyfactor/actions/.github/workflows/starter.yml@v4
15+
with:
16+
command_token_url: ${{ vars.COMMAND_TOKEN_URL }}
17+
command_hostname: ${{ vars.COMMAND_HOSTNAME }}
18+
command_base_api_path: ${{ vars.COMMAND_API_PATH }}
1519
secrets:
1620
token: ${{ secrets.V2BUILDTOKEN}}
17-
APPROVE_README_PUSH: ${{ secrets.APPROVE_README_PUSH}}
1821
gpg_key: ${{ secrets.KF_GPG_PRIVATE_KEY }}
1922
gpg_pass: ${{ secrets.KF_GPG_PASSPHRASE }}
20-
23+
scan_token: ${{ secrets.SAST_TOKEN }}
24+
entra_username: ${{ secrets.DOCTOOL_ENTRA_USERNAME }}
25+
entra_password: ${{ secrets.DOCTOOL_ENTRA_PASSWD }}
26+
command_client_id: ${{ secrets.COMMAND_CLIENT_ID }}
27+
command_client_secret: ${{ secrets.COMMAND_CLIENT_SECRET }}

AzureKeyVault/AzureClient.cs

Lines changed: 41 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -158,8 +158,17 @@ public virtual async Task<KeyVaultResource> CreateVault()
158158

159159
logger.LogTrace($"getting subscription info for provided subscription id {VaultProperties.SubscriptionId}");
160160

161-
SubscriptionResource subscription = KvManagementClient.GetSubscriptionResource(SubscriptionResource.CreateResourceIdentifier(VaultProperties.SubscriptionId));
162-
ResourceGroupResource resourceGroup = subscription.GetResourceGroup(VaultProperties.ResourceGroupName);
161+
var subscription = KvManagementClient.GetSubscriptionResource(SubscriptionResource.CreateResourceIdentifier(VaultProperties.SubscriptionId));
162+
163+
var resourceGroups = subscription.GetResourceGroups();
164+
ResourceGroupResource resourceGroup = await resourceGroups.GetAsync(VaultProperties.ResourceGroupName);
165+
logger.LogTrace("calling getAsync on resourcegroup...");
166+
await resourceGroup.GetAsync();
167+
logger.LogTrace("completed getAsync on resource group...");
168+
169+
var s = resourceGroup.HasData.ToString();
170+
171+
logger.LogTrace($"resource group has data?: {s}");
163172

164173
AzureLocation loc;
165174

@@ -170,7 +179,7 @@ public virtual async Task<KeyVaultResource> CreateVault()
170179
{
171180
logger.LogTrace($"no Vault Region location specified for new Vault, Getting available regions for resource group {resourceGroup.Data.Name}.");
172181
var locOptions = await resourceGroup.GetAvailableLocationsAsync();
173-
logger.LogTrace($"got location options for subscription {subscription.Data.SubscriptionId}", locOptions);
182+
logger.LogTrace($"got location options for subscription {VaultProperties.SubscriptionId}", locOptions);
174183
loc = locOptions.Value.FirstOrDefault();
175184
}
176185
catch (Exception ex)
@@ -269,33 +278,46 @@ public virtual async Task<IEnumerable<CurrentInventoryItem>> GetCertificatesAsyn
269278
{
270279
List<CurrentInventoryItem> inventoryItems = new List<CurrentInventoryItem>();
271280
AsyncPageable<CertificateProperties> inventory = null;
281+
var fullInventoryList = new List<CertificateProperties>();
282+
var failedCount = 0;
283+
Exception innerException = null;
284+
272285
try
273286
{
274287
logger.LogTrace("calling GetPropertiesOfCertificates() on the Certificate Client");
275288
inventory = CertClient.GetPropertiesOfCertificatesAsync();
289+
290+
logger.LogTrace($"created pageable request");
291+
292+
logger.LogTrace("iterating over result pages for complete list..");
276293

277-
logger.LogTrace($"got a pageable response");
294+
await foreach (var cert in inventory)
295+
{
296+
logger.LogTrace($"adding cert with ID: {cert.Id} to the list.");
297+
fullInventoryList.Add(cert); // convert to list from pages
298+
}
299+
300+
logger.LogTrace($"compiled full inventory list of {fullInventoryList.Count()} certificate(s)");
278301
}
279-
catch (Exception ex)
302+
catch (AuthenticationFailedException ex)
280303
{
281-
logger.LogError($"Error performing inventory. {ex.Message}", ex);
304+
logger.LogError($"Authentication failed: {ex.Message}");
305+
logger.LogError(LogHandler.FlattenException(ex));
282306
throw;
283307
}
284-
285-
logger.LogTrace("iterating over result pages for complete list..");
286-
287-
var fullInventoryList = new List<CertificateProperties>();
288-
var failedCount = 0;
289-
Exception innerException = null;
290-
291-
await foreach (var cert in inventory)
308+
catch (RequestFailedException ex) // Catch other potential Azure-specific errors
309+
{
310+
logger.LogError($"Azure Key Vault operation failed: {ex.Status} - {ex.Message}");
311+
logger.LogError(LogHandler.FlattenException(ex));
312+
throw;
313+
}
314+
catch (Exception ex)
292315
{
293-
logger.LogTrace($"adding cert with ID: {cert.Id} to the list.");
294-
fullInventoryList.Add(cert); // convert to list from pages
316+
logger.LogError($"Error performing inventory. {ex.Message}", ex);
317+
logger.LogError(LogHandler.FlattenException(ex));
318+
throw;
295319
}
296320

297-
logger.LogTrace($"compiled full inventory list of {fullInventoryList.Count()} certificate(s)");
298-
299321
foreach (var certificate in fullInventoryList)
300322
{
301323
logger.LogTrace($"getting details for the individual certificate with id: {certificate.Id} and name: {certificate.Name}");
@@ -317,8 +339,7 @@ public virtual async Task<IEnumerable<CurrentInventoryItem>> GetCertificatesAsyn
317339
catch (Exception ex)
318340
{
319341
failedCount++;
320-
innerException = ex;
321-
logger.LogError($"Failed to retreive details for certificate {certificate.Name}. Exception: {ex.Message}");
342+
logger.LogError($"Failed to retreive details for certificate {certificate.Name}. Exception: {LogHandler.FlattenException(ex)}");
322343
// continuing with inventory instead of throwing, in case there's an issue with a single certificate
323344
}
324345
}

AzureKeyVault/Jobs/AzureKeyVaultJob.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public void InitializeStore(dynamic config)
4040
// ClientSecret can be omitted for managed identities, required for service principal auth
4141
VaultProperties.ClientSecret = PAMUtilities.ResolvePAMField(PamSecretResolver, logger, "Server Password", config.ServerPassword);
4242

43-
if (VaultProperties.ClientSecret == null)
43+
if (string.IsNullOrEmpty(VaultProperties.ClientSecret))
4444
{
4545
logger.LogTrace("No client secret provided, assuming Managed Identity authentication");
4646
}

AzureKeyVault/Jobs/Management.cs

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
using Keyfactor.Orchestrators.Extensions.Interfaces;
1818
using System.Collections.Generic;
1919
using Newtonsoft.Json;
20-
using System.Security.AccessControl;
2120

2221
namespace Keyfactor.Extensions.Orchestrator.AzureKeyVault
2322
{
@@ -42,15 +41,18 @@ public JobResult ProcessJob(ManagementJobConfiguration config)
4241
{
4342
Result = OrchestratorJobStatusJobResult.Failure,
4443
FailureMessage = "Invalid Management Operation"
45-
};
46-
47-
string tagsJSON;
48-
bool preserveTags;
44+
};
4945

5046
logger.LogTrace("parsing entry parameters.. ");
51-
52-
tagsJSON = config.JobProperties[EntryParameters.TAGS] as string ?? string.Empty;
53-
preserveTags = config.JobProperties[EntryParameters.PRESERVE_TAGS] as bool? ?? false;
47+
string tagsJSON = string.Empty;
48+
bool preserveTags = false;
49+
if (config.JobProperties != null)
50+
{
51+
config.JobProperties.TryGetValue(EntryParameters.TAGS, out object tagsJSONObj);
52+
config.JobProperties.TryGetValue(EntryParameters.PRESERVE_TAGS, out object preserveTagsObj);
53+
tagsJSON = tagsJSONObj == null ? string.Empty : tagsJSONObj.ToString();
54+
preserveTags = preserveTagsObj == null ? false : Boolean.Parse(preserveTagsObj.ToString());
55+
}
5456

5557
switch (config.OperationType)
5658
{

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
- 3.1.11
2+
- bug fix for error when creating new Azure Keyvaults
3+
- documentation updates
4+
5+
- 3.1.10
6+
- bug fix for government cloud host name resolution
7+
18
- 3.1.9
29
- Added optional entry parameter to indicate that existing tags should be preserved if certificate is replaced
310
- bug fix for government cloud host name resolution

README.md

Lines changed: 60 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ The high level steps required to configure the Azure Keyvault Orchestrator exten
7070

7171
1) [Configure the Azure Keyvault for client access](#configure-the-azure-keyvault-for-client-access)
7272

73-
1) [Create the Store Type in Keyfactor](#create-the-akv-certificate-store-type)
73+
1) [Create the Store Type in Keyfactor](#akv-certificate-store-type)
7474

7575
1) [Install the Extension on the Orchestrator](#installation)
7676

@@ -544,7 +544,7 @@ To use the Azure Key Vault Universal Orchestrator extension, you **must** create
544544

545545

546546
The Azure Keyvault Certificate Store Type is designed to integrate with Microsoft Azure Key Vault, enabling users to
547-
manage and automate the lifecycle of cryptographic certificates stored in Azure Key Vault through Keyfactor Command.
547+
manage and automate the lifecycle of cryptographic certificates stored in Azure Keyvault through Keyfactor Command.
548548
This Certificate Store Type represents the connection and configuration necessary to interact with specific instances of
549549
Azure Key Vault, allowing for operations such as inventory, addition, removal, and discovery of certificates and
550550
certificate stores.
@@ -565,6 +565,11 @@ However, ensuring that the orchestrator has network access to Azure endpoints is
565565
mindful of these caveats and limitations will help ensure successful deployment and use of the Azure Keyvault
566566
Certificate Store Type within your organization’s security framework.
567567

568+
> :warning:
569+
> The alias you provide when enrolling a certificate will be used as the certificate name in Azure Keyvault.
570+
> Consequently; [it must _only_ contain alphanumeric characters and hyphens](https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/resource-name-rules#microsoftkeyvault).
571+
> If you encounter the error "The request URI contains an invalid name" when attempting to perform an enrollment, it is likely due to the use of disallowed characters in the alias.
572+
568573

569574

570575

@@ -633,7 +638,7 @@ the Keyfactor Command Portal
633638
##### Advanced Tab
634639
| Attribute | Value | Description |
635640
| --------- | ----- | ----- |
636-
| Supports Custom Alias | Optional | Determines if an individual entry within a store can have a custom Alias. |
641+
| Supports Custom Alias | Required | Determines if an individual entry within a store can have a custom Alias. |
637642
| Private Key Handling | Optional | This determines if Keyfactor can send the private key associated with a certificate to the store. Required because IIS certificates without private keys would be invalid. |
638643
| PFX Password Style | Default | 'Default' - PFX password is randomly generated, 'Custom' - PFX password may be specified when the enrollment job is created (Requires the Allow Custom Password application setting to be enabled.) |
639644

@@ -658,6 +663,44 @@ the Keyfactor Command Portal
658663

659664
![AKV Custom Fields Tab](docsource/images/AKV-custom-fields-store-type-dialog.png)
660665

666+
667+
###### Tenant Id
668+
The ID of the primary Azure Tenant where the KeyVaults are hosted
669+
670+
![AKV Custom Field - TenantId](docsource/images/AKV-custom-field-TenantId-dialog.png)
671+
672+
673+
674+
###### SKU Type
675+
The SKU type for newly created KeyVaults (only needed if needing to create new KeyVaults in your Azure subscription via Command)
676+
677+
![AKV Custom Field - SkuType](docsource/images/AKV-custom-field-SkuType-dialog.png)
678+
679+
680+
681+
###### Vault Region
682+
The Azure Region to put newly created KeyVaults (only needed if needing to create new KeyVaults in your Azure subscription via Command)
683+
684+
![AKV Custom Field - VaultRegion](docsource/images/AKV-custom-field-VaultRegion-dialog.png)
685+
686+
687+
688+
###### Azure Cloud
689+
The Azure Cloud where the KeyVaults are located (only necessary if not using the standard Azure Public cloud)
690+
691+
![AKV Custom Field - AzureCloud](docsource/images/AKV-custom-field-AzureCloud-dialog.png)
692+
693+
694+
695+
###### Private KeyVault Endpoint
696+
The private endpoint of your vault instance (if a private endpoint is configured in Azure)
697+
698+
![AKV Custom Field - PrivateEndpoint](docsource/images/AKV-custom-field-PrivateEndpoint-dialog.png)
699+
700+
701+
702+
703+
661704
##### Entry Parameters Tab
662705

663706
| Name | Display Name | Description | Type | Default Value | Entry has a private key | Adding an entry | Removing an entry | Reenrolling an entry |
@@ -669,6 +712,20 @@ the Keyfactor Command Portal
669712

670713
![AKV Entry Parameters Tab](docsource/images/AKV-entry-parameters-store-type-dialog.png)
671714

715+
716+
##### Certificate Tags
717+
If desired, tags can be applied to the KeyVault entries. Provide them as a JSON string of key-value pairs ie: '{'tag-name': 'tag-content', 'other-tag-name': 'other-tag-content'}'
718+
719+
![AKV Entry Parameter - CertificateTags](docsource/images/AKV-entry-parameters-store-type-dialog-CertificateTags.png)
720+
721+
722+
##### Preserve Existing Tags
723+
If true, this will perform a union of any tags provided with enrollment with the tags on the existing cert with the same alias and apply the result to the new certificate.
724+
725+
![AKV Entry Parameter - PreserveExistingTags](docsource/images/AKV-entry-parameters-store-type-dialog-PreserveExistingTags.png)
726+
727+
728+
672729
</details>
673730

674731
## Installation

docsource/akv.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
## Overview
22

33
The Azure Keyvault Certificate Store Type is designed to integrate with Microsoft Azure Key Vault, enabling users to
4-
manage and automate the lifecycle of cryptographic certificates stored in Azure Key Vault through Keyfactor Command.
4+
manage and automate the lifecycle of cryptographic certificates stored in Azure Keyvault through Keyfactor Command.
55
This Certificate Store Type represents the connection and configuration necessary to interact with specific instances of
66
Azure Key Vault, allowing for operations such as inventory, addition, removal, and discovery of certificates and
77
certificate stores.
@@ -22,3 +22,8 @@ However, ensuring that the orchestrator has network access to Azure endpoints is
2222
mindful of these caveats and limitations will help ensure successful deployment and use of the Azure Keyvault
2323
Certificate Store Type within your organization’s security framework.
2424

25+
> :warning:
26+
> The alias you provide when enrolling a certificate will be used as the certificate name in Azure Keyvault.
27+
> Consequently; [it must _only_ contain alphanumeric characters and hyphens](https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/resource-name-rules#microsoftkeyvault).
28+
> If you encounter the error "The request URI contains an invalid name" when attempting to perform an enrollment, it is likely due to the use of disallowed characters in the alias.
29+

docsource/content.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ The high level steps required to configure the Azure Keyvault Orchestrator exten
2525

2626
1) [Configure the Azure Keyvault for client access](#configure-the-azure-keyvault-for-client-access)
2727

28-
1) [Create the Store Type in Keyfactor](#create-the-akv-certificate-store-type)
28+
1) [Create the Store Type in Keyfactor](#akv-certificate-store-type)
2929

3030
1) [Install the Extension on the Orchestrator](#installation)
3131

-5.29 KB
Loading

0 commit comments

Comments
 (0)