Add -Kind switch to Get-InfisicalCertificateAuthority

List parameter set gains -Kind Internal|Acme|Any. Internal (default) preserves current behavior against /api/v1/cert-manager/ca/internal. Any binds to the generic /api/v1/cert-manager/ca endpoint returning both internal and ACME CAs. Acme uses the generic endpoint and client-side filters to type=acme. ById retrieval is unchanged and still resolves against the internal CA endpoint. The existing InfisicalCertificateAuthority model already exposes a Type property to distinguish entries when -Kind Any is used. MAML help updated.
This commit is contained in:
GraceSolutions
2026-06-04 16:56:40 -04:00
parent 9efdafb7fb
commit c9c8a8446b
6 changed files with 85 additions and 5 deletions
+1
View File
@@ -9,6 +9,7 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) loos
- Infisical API error responses are now parsed to surface the server-side `message`, `error`, and `reqId` fields. The 4xx/5xx exception message includes the human-readable explanation (e.g. "The project is of type secret-manager") instead of an opaque `Infisical API returned 400 (Bad Request)`. The `InfisicalApiException` gains `ApiErrorMessage` and `ApiRequestId` properties; `InfisicalErrorDetails` carries the same fields so PowerShell error records and logger output expose them. - Infisical API error responses are now parsed to surface the server-side `message`, `error`, and `reqId` fields. The 4xx/5xx exception message includes the human-readable explanation (e.g. "The project is of type secret-manager") instead of an opaque `Infisical API returned 400 (Bad Request)`. The `InfisicalApiException` gains `ApiErrorMessage` and `ApiRequestId` properties; `InfisicalErrorDetails` carries the same fields so PowerShell error records and logger output expose them.
- `Get-InfisicalCertificateProfile` added with `List` (default) and `ById` parameter sets. List binds to `GET /api/v1/cert-manager/certificate-profiles` (optional `-Limit`, `-Offset`, `-IncludeConfigs`); ById binds to `GET /api/v1/cert-manager/certificate-profiles/{certificateProfileId}`. New `InfisicalCertificateProfile` model surfaces ca/policy ids, slug, enrollment type, per-profile defaults (ttl, key/extended key usages), and the embedded CA/policy/apiConfig summaries. - `Get-InfisicalCertificateProfile` added with `List` (default) and `ById` parameter sets. List binds to `GET /api/v1/cert-manager/certificate-profiles` (optional `-Limit`, `-Offset`, `-IncludeConfigs`); ById binds to `GET /api/v1/cert-manager/certificate-profiles/{certificateProfileId}`. New `InfisicalCertificateProfile` model surfaces ca/policy ids, slug, enrollment type, per-profile defaults (ttl, key/extended key usages), and the embedded CA/policy/apiConfig summaries.
- `Get-InfisicalCertificatePolicy` added with `List` (default) and `ById` parameter sets. List binds to `GET /api/v1/cert-manager/certificate-policies` (optional `-Limit`, `-Offset`); ById binds to `GET /api/v1/cert-manager/certificate-policies/{certificatePolicyId}`. New `InfisicalCertificatePolicy` model surfaces subject, SANs, key usages, extended key usages, algorithms, and validity. Polymorphic string-or-array fields (`allowed`, `required`, `keyAlgorithm`) are normalized to arrays; `sans` is normalized whether the API returns an object or an array. - `Get-InfisicalCertificatePolicy` added with `List` (default) and `ById` parameter sets. List binds to `GET /api/v1/cert-manager/certificate-policies` (optional `-Limit`, `-Offset`); ById binds to `GET /api/v1/cert-manager/certificate-policies/{certificatePolicyId}`. New `InfisicalCertificatePolicy` model surfaces subject, SANs, key usages, extended key usages, algorithms, and validity. Polymorphic string-or-array fields (`allowed`, `required`, `keyAlgorithm`) are normalized to arrays; `sans` is normalized whether the API returns an object or an array.
- `Get-InfisicalCertificateAuthority` gains a `-Kind` parameter on the List parameter set with values `Internal` (default, preserves prior behavior against `/api/v1/cert-manager/ca/internal`), `Any` (binds to the generic `/api/v1/cert-manager/ca` endpoint which returns both internal and ACME CAs), and `Acme` (uses the generic endpoint and client-side filters to ACME issuers only). ById retrieval is unchanged and still resolves against the internal CA endpoint.
## 2026.06.04.1920 ## 2026.06.04.1920
@@ -1006,17 +1006,17 @@ $RemoveInfisicalTagResult = Remove-InfisicalTag @RemoveInfisicalTagParameters</d
<command:command xmlns:maml="http://schemas.microsoft.com/maml/2004/10" xmlns:command="http://schemas.microsoft.com/maml/dev/command/2004/10" xmlns:dev="http://schemas.microsoft.com/maml/dev/2004/10"> <command:command xmlns:maml="http://schemas.microsoft.com/maml/2004/10" xmlns:command="http://schemas.microsoft.com/maml/dev/command/2004/10" xmlns:dev="http://schemas.microsoft.com/maml/dev/2004/10">
<command:details> <command:details>
<command:name>Get-InfisicalCertificateAuthority</command:name> <command:name>Get-InfisicalCertificateAuthority</command:name>
<maml:description><maml:para>Lists or retrieves Infisical internal Certificate Authorities.</maml:para></maml:description> <maml:description><maml:para>Lists or retrieves Infisical Certificate Authorities.</maml:para></maml:description>
<command:verb>Get</command:verb> <command:verb>Get</command:verb>
<command:noun>InfisicalCertificateAuthority</command:noun> <command:noun>InfisicalCertificateAuthority</command:noun>
</command:details> </command:details>
<maml:description> <maml:description>
<maml:para>When -CaId is supplied (ById parameter set) returns a single CA. Otherwise (List parameter set) returns every internal CA visible in the project. -ProjectId defaults to the session-pinned project when omitted.</maml:para> <maml:para>When -CaId is supplied (ById parameter set) returns a single internal CA. Otherwise (List parameter set) returns CAs scoped by -Kind: Internal (default, /api/v1/cert-manager/ca/internal), Any (/api/v1/cert-manager/ca returning both internal and ACME), or Acme (filters the generic endpoint to ACME issuers only). -ProjectId defaults to the session-pinned project when omitted.</maml:para>
</maml:description> </maml:description>
<maml:alertSet> <maml:alertSet>
<maml:title>Notes</maml:title> <maml:title>Notes</maml:title>
<maml:alert> <maml:alert>
<maml:para>Only internal CAs are surfaced; external/ACME issuers are not enumerated by this cmdlet. CA Ids returned here are the values to pass on -CertificateAuthorityId to Request-InfisicalCertificate.</maml:para> <maml:para>ByID retrieval currently always resolves against the internal CA endpoint. CA Ids returned here are the values to pass on -CertificateAuthorityId to Request-InfisicalCertificate. The Type property distinguishes 'internal' from 'acme' when -Kind Any is used.</maml:para>
</maml:alert> </maml:alert>
</maml:alertSet> </maml:alertSet>
<command:examples> <command:examples>
@@ -1027,6 +1027,11 @@ $RemoveInfisicalTagResult = Remove-InfisicalTag @RemoveInfisicalTagParameters</d
</command:example> </command:example>
<command:example> <command:example>
<maml:title>EXAMPLE 2</maml:title> <maml:title>EXAMPLE 2</maml:title>
<dev:code>Get-InfisicalCertificateAuthority -Kind Any</dev:code>
<dev:remarks><maml:para>Lists every CA (internal and ACME) visible in the session-pinned project; inspect the Type property to distinguish them.</maml:para></dev:remarks>
</command:example>
<command:example>
<maml:title>EXAMPLE 3</maml:title>
<dev:code>$GetInfisicalCertificateAuthorityListResult = Get-InfisicalCertificateAuthority | Where-Object { $_.FriendlyName -eq 'Issuing CA - Platform' } <dev:code>$GetInfisicalCertificateAuthorityListResult = Get-InfisicalCertificateAuthority | Where-Object { $_.FriendlyName -eq 'Issuing CA - Platform' }
$GetInfisicalCertificateAuthorityParameters = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary' -ArgumentList ([System.StringComparer]::OrdinalIgnoreCase) $GetInfisicalCertificateAuthorityParameters = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary' -ArgumentList ([System.StringComparer]::OrdinalIgnoreCase)
@@ -1035,7 +1040,7 @@ $GetInfisicalCertificateAuthorityParameters.ProjectId = $ConnectInfisicalParamet
$GetInfisicalCertificateAuthorityParameters.Verbose = $True $GetInfisicalCertificateAuthorityParameters.Verbose = $True
$GetInfisicalCertificateAuthorityResult = Get-InfisicalCertificateAuthority @GetInfisicalCertificateAuthorityParameters</dev:code> $GetInfisicalCertificateAuthorityResult = Get-InfisicalCertificateAuthority @GetInfisicalCertificateAuthorityParameters</dev:code>
<dev:remarks><maml:para>Filters the CA list by friendly name and then re-fetches the canonical CA record by id.</maml:para></dev:remarks> <dev:remarks><maml:para>Filters the CA list by friendly name and then re-fetches the canonical CA record by id using a splatted parameter set.</maml:para></dev:remarks>
</command:example> </command:example>
</command:examples> </command:examples>
</command:command> </command:command>
@@ -16,6 +16,10 @@ namespace PSInfisicalAPI.Cmdlets
[Parameter] public string ProjectId { get; set; } [Parameter] public string ProjectId { get; set; }
[Parameter(ParameterSetName = "List")]
[ValidateSet("Internal", "Acme", "Any")]
public string Kind { get; set; } = "Internal";
protected override void ProcessRecord() protected override void ProcessRecord()
{ {
try try
@@ -34,7 +38,20 @@ namespace PSInfisicalAPI.Cmdlets
return; return;
} }
InfisicalCertificateAuthority[] all = client.ListInternalCertificateAuthorities(connection, ProjectId); InfisicalCertificateAuthority[] all;
if (string.Equals(Kind, "Internal", StringComparison.OrdinalIgnoreCase))
{
all = client.ListInternalCertificateAuthorities(connection, ProjectId);
}
else
{
all = client.ListAllCertificateAuthorities(connection, ProjectId);
if (string.Equals(Kind, "Acme", StringComparison.OrdinalIgnoreCase))
{
all = FilterByType(all, "acme");
}
}
foreach (InfisicalCertificateAuthority ca in all) foreach (InfisicalCertificateAuthority ca in all)
{ {
WriteObject(ca); WriteObject(ca);
@@ -45,5 +62,20 @@ namespace PSInfisicalAPI.Cmdlets
ThrowTerminatingForException("GetInfisicalCertificateAuthorityCmdlet", "GetCertificateAuthority", exception); ThrowTerminatingForException("GetInfisicalCertificateAuthorityCmdlet", "GetCertificateAuthority", exception);
} }
} }
private static InfisicalCertificateAuthority[] FilterByType(InfisicalCertificateAuthority[] source, string type)
{
if (source == null || source.Length == 0) { return Array.Empty<InfisicalCertificateAuthority>(); }
System.Collections.Generic.List<InfisicalCertificateAuthority> kept = new System.Collections.Generic.List<InfisicalCertificateAuthority>();
foreach (InfisicalCertificateAuthority ca in source)
{
if (ca != null && string.Equals(ca.Type, type, StringComparison.OrdinalIgnoreCase))
{
kept.Add(ca);
}
}
return kept.ToArray();
}
} }
} }
@@ -60,5 +60,7 @@ namespace PSInfisicalAPI.Endpoints
public const string ListCertificatePolicies = "ListCertificatePolicies"; public const string ListCertificatePolicies = "ListCertificatePolicies";
public const string GetCertificatePolicy = "GetCertificatePolicy"; public const string GetCertificatePolicy = "GetCertificatePolicy";
public const string ListCertificateAuthorities = "ListCertificateAuthorities";
} }
} }
@@ -682,6 +682,16 @@ namespace PSInfisicalAPI.Endpoints
Template = "/api/v1/cert-manager/certificate-policies/{certificatePolicyId}", Template = "/api/v1/cert-manager/certificate-policies/{certificatePolicyId}",
RequiresAuthorization = true RequiresAuthorization = true
}); });
Add(map, new InfisicalEndpointDefinition
{
Name = InfisicalEndpointNames.ListCertificateAuthorities,
Resource = "Pki",
Version = "v1",
Method = "GET",
Template = "/api/v1/cert-manager/ca",
RequiresAuthorization = true
});
} }
public static InfisicalEndpointDefinition Get(string name) public static InfisicalEndpointDefinition Get(string name)
@@ -91,6 +91,36 @@ namespace PSInfisicalAPI.Pki
} }
} }
public InfisicalCertificateAuthority[] ListAllCertificateAuthorities(InfisicalConnection connection, string projectId)
{
if (connection == null) { throw new ArgumentNullException(nameof(connection)); }
string resolvedProjectId = FirstNonEmpty(projectId, connection.ProjectId);
if (string.IsNullOrEmpty(resolvedProjectId)) { throw new InfisicalConfigurationException("ProjectId is required."); }
List<KeyValuePair<string, string>> query = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("projectId", resolvedProjectId)
};
try
{
_logger.Information(Component, "Attempting to list Infisical certificate authorities. Please Wait...");
InfisicalHttpResponse response = _invoker.InvokeWithCandidateFallback(connection, InfisicalEndpointNames.ListCertificateAuthorities, "ListCertificateAuthorities", null, query, null);
string body = response.Body;
response.Clear();
List<InfisicalInternalCaResponseDto> source = ParseCaListBody(body);
InfisicalCertificateAuthority[] mapped = InfisicalCaMapper.MapMany(source, resolvedProjectId);
_logger.Information(Component, "Infisical certificate authority list retrieval was successful.");
return mapped;
}
catch (Exception)
{
_logger.Error(Component, "Infisical certificate authority list retrieval failed.");
throw;
}
}
public InfisicalCertificate RetrieveCertificate(InfisicalConnection connection, string identifier) public InfisicalCertificate RetrieveCertificate(InfisicalConnection connection, string identifier)
{ {
if (connection == null) { throw new ArgumentNullException(nameof(connection)); } if (connection == null) { throw new ArgumentNullException(nameof(connection)); }