Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 0 additions & 20 deletions .github/workflows/keyfactor-bootstrap-workflow-v3.yml

This file was deleted.

12 changes: 10 additions & 2 deletions .github/workflows/keyfactor-bootstrap-workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,17 @@ on:

jobs:
call-starter-workflow:
uses: keyfactor/actions/.github/workflows/starter.yml@v2
uses: keyfactor/actions/.github/workflows/starter.yml@v4
with:
command_token_url: ${{ vars.COMMAND_TOKEN_URL }}
command_hostname: ${{ vars.COMMAND_HOSTNAME }}
command_base_api_path: ${{ vars.COMMAND_API_PATH }}
secrets:
token: ${{ secrets.V2BUILDTOKEN}}
APPROVE_README_PUSH: ${{ secrets.APPROVE_README_PUSH}}
gpg_key: ${{ secrets.KF_GPG_PRIVATE_KEY }}
gpg_pass: ${{ secrets.KF_GPG_PASSPHRASE }}
scan_token: ${{ secrets.SAST_TOKEN }}
entra_username: ${{ secrets.DOCTOOL_ENTRA_USERNAME }}
entra_password: ${{ secrets.DOCTOOL_ENTRA_PASSWD }}
command_client_id: ${{ secrets.COMMAND_CLIENT_ID }}
command_client_secret: ${{ secrets.COMMAND_CLIENT_SECRET }}
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
## 1.0.1
* added retrieval of roles associated with enrolled certificates via metadata for Vault Enterprise users

## 1.0.0
* initial release
2 changes: 1 addition & 1 deletion hashicorp-vault-cagateway/APIProxy/CertResponse.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2024 Keyfactor
// Copyright 2025 Keyfactor
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
Expand Down
2 changes: 1 addition & 1 deletion hashicorp-vault-cagateway/APIProxy/ErrorResponse.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2024 Keyfactor
// Copyright 2025 Keyfactor
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
Expand Down
2 changes: 1 addition & 1 deletion hashicorp-vault-cagateway/APIProxy/KeyedList.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2024 Keyfactor
// Copyright 2025 Keyfactor
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
Expand Down
30 changes: 30 additions & 0 deletions hashicorp-vault-cagateway/APIProxy/MetadataResponse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Copyright 2025 Keyfactor
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions
// and limitations under the License.

using System;
using System.Text.Json.Serialization;

namespace Keyfactor.Extensions.CAPlugin.HashicorpVault.APIProxy
{
public class MetadataResponse
{
[JsonPropertyName("issuer_id")]
public string IssuerId { get; set; }

[JsonPropertyName("expiration")]
public DateTime? Expiration { get; set; }

[JsonPropertyName("cert_metadata")]
public string CertMetadata { get; set; }

[JsonPropertyName("role")]
public string Role { get; set; }

[JsonPropertyName("serial_number")]
public string SerialNumber { get; set; }
}
}
2 changes: 1 addition & 1 deletion hashicorp-vault-cagateway/APIProxy/RevokeRequest.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2024 Keyfactor
// Copyright 2025 Keyfactor
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
Expand Down
2 changes: 1 addition & 1 deletion hashicorp-vault-cagateway/APIProxy/RevokeResponse.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2024 Keyfactor
// Copyright 2025 Keyfactor
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
Expand Down
2 changes: 1 addition & 1 deletion hashicorp-vault-cagateway/APIProxy/SealStatusResponse.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2024 Keyfactor
// Copyright 2025 Keyfactor
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
Expand Down
2 changes: 1 addition & 1 deletion hashicorp-vault-cagateway/APIProxy/SignRequest.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2024 Keyfactor
// Copyright 2025 Keyfactor
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
Expand Down
2 changes: 1 addition & 1 deletion hashicorp-vault-cagateway/APIProxy/SignResponse.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2024 Keyfactor
// Copyright 2025 Keyfactor
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
Expand Down
2 changes: 1 addition & 1 deletion hashicorp-vault-cagateway/APIProxy/TokenLookupResponse.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2024 Keyfactor
// Copyright 2025 Keyfactor
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
Expand Down
2 changes: 1 addition & 1 deletion hashicorp-vault-cagateway/APIProxy/WrappedResponse.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2024 Keyfactor
// Copyright 2025 Keyfactor
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
Expand Down
37 changes: 36 additions & 1 deletion hashicorp-vault-cagateway/Client/HashicorpVaultClient.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2024 Keyfactor
// Copyright 2025 Keyfactor
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
Expand Down Expand Up @@ -246,6 +246,41 @@ public async Task<List<string>> GetRoleNamesAsync()
finally { logger.MethodExit(); }
}

/// <summary>
/// Retreives the metadata for the certificate
/// </summary>
/// <param name="certSerial"></param>
/// <returns></returns>
public async Task<MetadataResponse> GetCertMetadata(string certSerial)
{
logger.MethodEntry();

try
{
var res = await _vaultHttp.GetAsync<WrappedResponse<MetadataResponse>>($"cert-metadata/{certSerial}");
var md = res?.Data;
if (md != null)
{
logger.LogTrace($"got response from cert-metadata");
logger.LogTrace($"serial number: {md.SerialNumber}");
logger.LogTrace($"issuer id: {md.IssuerId}");
logger.LogTrace($"expiration: {md.Expiration}");
logger.LogTrace($"metadata: {md.CertMetadata}");
logger.LogTrace($"role: {md.Role}");
}
else {
logger.LogTrace($"no metadata associated with cert {certSerial} could be found.");
}
return md;
}
catch (Exception ex)
{
logger.LogError($"an error occurred when attempting to retreive the certificate metadata: {ex.Message}");
throw;
}
finally { logger.MethodExit(); }
}

private void SetClientValuesFromConfigs(HashicorpVaultCAConfig caConfig, HashicorpVaultCATemplateConfig templateConfig)
{
logger.MethodEntry();
Expand Down
3 changes: 2 additions & 1 deletion hashicorp-vault-cagateway/Client/VaultHttp.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2024 Keyfactor
// Copyright 2025 Keyfactor
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
Expand Down Expand Up @@ -77,6 +77,7 @@ public async Task<T> GetAsync<T>(string path, Dictionary<string, string> paramet
if (parameters != null) { request.AddJsonBody(parameters); }

var response = await _restClient.ExecuteGetAsync<T>(request);
logger.LogTrace($"raw response: {response.Content}");

response.ThrowIfError();

Expand Down
2 changes: 1 addition & 1 deletion hashicorp-vault-cagateway/Constants.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2024 Keyfactor
// Copyright 2025 Keyfactor
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
Expand Down
6 changes: 3 additions & 3 deletions hashicorp-vault-cagateway/HashicorpVaultCAConfig.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2024 Keyfactor
// Copyright 2025 Keyfactor
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
Expand All @@ -23,8 +23,8 @@ public class HashicorpVaultCAConfig
[JsonPropertyName(Constants.CAConfig.NAMESPACE)]
public string Namespace { get; set; }

[JsonPropertyName(Constants.CAConfig.CLIENTCERT)]
public AuthCert ClientCertificate { get; set; }
//[JsonPropertyName(Constants.CAConfig.CLIENTCERT)]
//public AuthCert ClientCertificate { get; set; }

[JsonPropertyName(Constants.CAConfig.ENABLED)]
public bool Enabled { get; set; }
Expand Down
45 changes: 33 additions & 12 deletions hashicorp-vault-cagateway/HashicorpVaultCAConnector.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2024 Keyfactor
// Copyright 2025 Keyfactor
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
Expand Down Expand Up @@ -26,7 +26,7 @@
private readonly ILogger logger;
private HashicorpVaultCAConfig _caConfig { get; set; }
private HashicorpVaultClient _client { get; set; }
private ICertificateDataReader _certificateDataReader;

Check warning on line 29 in hashicorp-vault-cagateway/HashicorpVaultCAConnector.cs

View workflow job for this annotation

GitHub Actions / call-starter-workflow / call-generate-readme-workflow / Use private doctool action in public repository

Field 'HashicorpVaultCAConnector._certificateDataReader' is never assigned to, and will always have its default value null

Check warning on line 29 in hashicorp-vault-cagateway/HashicorpVaultCAConnector.cs

View workflow job for this annotation

GitHub Actions / call-starter-workflow / call-generate-readme-workflow / Use private doctool action in public repository

Field 'HashicorpVaultCAConnector._certificateDataReader' is never assigned to, and will always have its default value null

Check warning on line 29 in hashicorp-vault-cagateway/HashicorpVaultCAConnector.cs

View workflow job for this annotation

GitHub Actions / call-starter-workflow / call-dotnet-build-and-release-workflow / dotnet-build-and-release

Field 'HashicorpVaultCAConnector._certificateDataReader' is never assigned to, and will always have its default value null

Check warning on line 29 in hashicorp-vault-cagateway/HashicorpVaultCAConnector.cs

View workflow job for this annotation

GitHub Actions / call-starter-workflow / call-dotnet-build-and-release-workflow / dotnet-build-and-release

Field 'HashicorpVaultCAConnector._certificateDataReader' is never assigned to, and will always have its default value null
private JsonSerializerOptions _serializerOptions;

public HashicorpVaultCAConnector()
Expand Down Expand Up @@ -263,7 +263,7 @@
}
logger.LogTrace($"converting {certSerial} to database trackingId");

var trackingId = certSerial.Replace(":", "-"); // we store with '-'; hashi stores with ':'
var trackingId = certSerial.Replace(":", "-"); // we store with '-'; hashi stores with ':'

// then, check for an existing local entry
try
Expand All @@ -280,14 +280,33 @@
{
logger.LogTrace($"adding cert with serial {trackingId} to the database. fullsync is {fullSync}, and the certificate {(dbStatus == -1 ? "does not yet exist" : "already exists")} in the database.");

logger.LogTrace("attempting to retreive the role name (productId) from the certificate metadata, if available");

var metaData = new MetadataResponse();

try
{
metaData = await _client.GetCertMetadata(certSerial);
}
catch (Exception)
{
logger.LogTrace("an error occurred when attempting to retreive the metadata, continuing..");
}

var newCert = new AnyCAPluginCertificate
{
CARequestID = trackingId,
Certificate = certFromVault.Certificate,
Status = certFromVault.RevocationTime != null ? (int)EndEntityStatus.REVOKED : (int)EndEntityStatus.GENERATED,
RevocationDate = certFromVault.RevocationTime,
RevocationDate = certFromVault.RevocationTime,
};

// if we were able to get the role name from metadata, we include it
if (!string.IsNullOrEmpty(metaData?.Role))
{
newCert.ProductID = metaData.Role;
}

try
{
logger.LogTrace($"writing the result.");
Expand Down Expand Up @@ -327,8 +346,9 @@
/// </summary>
/// <param name="connectionInfo">The information used to connect to the CA.</param>
public async Task ValidateCAConnectionInfo(Dictionary<string, object> connectionInfo)
{
{
logger.MethodEntry();
logger.LogTrace(message: $"Validating CA connection info: {JsonSerializer.Serialize(connectionInfo)}");

// first, we check to see if the CA Gateway is enabled in the configuration
if (!(bool)connectionInfo[Constants.CAConfig.ENABLED])
Expand All @@ -352,7 +372,10 @@

// make sure an authentication mechanism is defined (either certificate or token)
var token = connectionInfo[Constants.CAConfig.TOKEN] as string;
var cert = connectionInfo[Constants.CAConfig.CLIENTCERT] as string;

//var cert = connectionInfo[Constants.CAConfig.CLIENTCERT] as string;

var cert = string.Empty; // temporary until client cert auth into vault is implemented

if (string.IsNullOrEmpty(token) && string.IsNullOrEmpty(cert))
{
Expand Down Expand Up @@ -422,14 +445,17 @@
public Task ValidateProductInfo(EnrollmentProductInfo productInfo, Dictionary<string, object> connectionInfo)
{
logger.MethodEntry();

logger.LogTrace($"validating product info: {JsonSerializer.Serialize(productInfo)}");

List<string> errors = new List<string>();

HashicorpVaultCATemplateConfig templateConfig = null;
HashicorpVaultCAConfig caConfig = null;
// deserialize the values
try
{
templateConfig = JsonSerializer.Deserialize<HashicorpVaultCATemplateConfig>(JsonSerializer.Serialize(productInfo));
templateConfig = JsonSerializer.Deserialize<HashicorpVaultCATemplateConfig>(JsonSerializer.Serialize(productInfo.ProductParameters));
caConfig = JsonSerializer.Deserialize<HashicorpVaultCAConfig>(JsonSerializer.Serialize(connectionInfo));
logger.LogTrace("successfully deserialized the product and CA config values.");
}
Expand All @@ -439,12 +465,7 @@
logger.LogError(LogHandler.FlattenException(ex));
throw;
}
// make sure Role Name is present in the template config
if (string.IsNullOrEmpty(productInfo.ProductParameters[Constants.TemplateConfig.ROLENAME] as string))
{
errors.Add($"The '{Constants.TemplateConfig.ROLENAME}' is required.");
}


// if any errors, throw
if (errors.Any())
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2024 Keyfactor
// Copyright 2025 Keyfactor
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
Expand Down
1 change: 1 addition & 0 deletions integration-manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"description": "Hashicorp Vault plugin for the AnyCA REST Gateway Framework",
"gateway_framework": "24.2.0",
"release_dir": "hashicorp-vault-cagateway/bin/Release",
"release_project": "hashicorp-vault-cagateway\\hashicorp-vault-caplugin.csproj",
"about": {
"carest": {
"product_ids": [],
Expand Down
15 changes: 15 additions & 0 deletions readme_source.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,21 @@ Make sure the following information is available, as it will be needed to comple
- An authentication token that has sufficient authority to perform operations on the PKI Secrets engine
- PKI Secrets Engine Roles defined that will correspond to certificate templates to be used when signing certificates with the CA.

### Managing Certificates Issued Outside of Keyfactor Command

:warning: Important!

The role name used when issuing the certificate is required in order to store the associated details for the certificate within Keyfactor Command.
The Hashicorp Vault PKI Secrets Engine does not store the role name by default.

Because of this, certificates generated outside of Keyfactor Command will _not_ have their associated data available within Command **unless the following two conditions are met**:
- The certificate was generated in an instance of Hashicorp Vault with the Enterprise License, to allow for certificate metadata to be stored.
- There is certificate metadata associated with the certificate

The metadata value provided when the cert is issued outside of Command can be blank, it just needs to have been provided in order for the role used for issuance to be stored.
Certificates issued for the Hashicorp Vault CA from within the Keyfactor Command platform do not need to have metadata associated with it in order to view the certificate details.


### Steps

1. Install the AnyCA Gateway Rest per the [official Keyfactor documentation](https://software.keyfactor.com/Guides/AnyCAGatewayREST/Content/AnyCAGatewayREST/InstallIntroduction.htm).
Expand Down
Loading