Skip to content

Commit a225987

Browse files
Update external cert manager support
1 parent 902bf9b commit a225987

File tree

7 files changed

+82
-26
lines changed

7 files changed

+82
-26
lines changed

src/Certify.Core/Management/CertifyManager/CertifyManager.ManagedCertificates.cs

Lines changed: 65 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,23 @@ public partial class CertifyManager
2525
/// <returns></returns>
2626
public async Task<ManagedCertificate> GetManagedCertificate(string id)
2727
{
28-
var item = await _itemManager.GetById(id);
29-
if (item != null)
28+
if (id.StartsWith("ext-"))
3029
{
31-
item.InstanceId = _serverConfig.HubAssignedInstanceId;
32-
item.DateRetrieved = DateTime.UtcNow;
30+
// look for item via external managed certificate provider
31+
return _externallyManagedCertificatesCache
32+
.FirstOrDefault(i => i.Id == id);
3333
}
34+
else
35+
{
36+
var item = await _itemManager.GetById(id);
37+
if (item != null)
38+
{
39+
item.InstanceId = _serverConfig.HubAssignedInstanceId;
40+
item.DateRetrieved = DateTime.UtcNow;
41+
}
3442

35-
return item;
43+
return item;
44+
}
3645
}
3746

3847
/// <summary>
@@ -58,47 +67,70 @@ public async Task<List<ManagedCertificate>> GetManagedCertificates(ManagedCertif
5867
return list;
5968
}
6069

70+
List<ManagedCertificate> _externallyManagedCertificatesCache = [];
71+
private DateTimeOffset _externallyManagedCacheUpdated = DateTimeOffset.MinValue;
72+
6173
private async Task<List<ManagedCertificate>> GetExternallyManagedCertificates(ManagedCertificateFilter filter)
6274
{
63-
var externalList = new List<ManagedCertificate>();
75+
if (_externallyManagedCacheUpdated > DateTimeOffset.UtcNow.AddMinutes(-10))
76+
{
77+
// return cached results
78+
return _externallyManagedCertificatesCache;
79+
}
80+
6481
if (_pluginManager?.CertificateManagerProviders?.Any() == true)
6582
{
66-
// TODO: cache providers/results
83+
List<ManagedCertificate> list = [];
6784

6885
// check if we have any external sources of managed certificates
6986
foreach (var p in _pluginManager.CertificateManagerProviders)
7087
{
7188
if (p != null)
7289
{
73-
var pluginType = p.GetType();
74-
var providers = p.GetProviders(pluginType);
75-
76-
foreach (var cp in providers)
90+
try
7791
{
78-
if (cp?.IsEnabled == true)
79-
{
80-
try
81-
{
82-
var certManager = p.GetProvider(pluginType, cp.Id);
83-
var certs = await certManager.GetManagedCertificates(filter);
92+
var pluginType = p.GetType();
93+
var providers = p.GetProviders(pluginType);
8494

85-
externalList.AddRange(certs);
86-
}
87-
catch (Exception ex)
95+
foreach (var cp in providers)
96+
{
97+
if (cp?.IsEnabled == true)
8898
{
89-
_serviceLog?.Error($"Failed to query certificate manager plugin {cp.Title} {ex}");
99+
try
100+
{
101+
var certManager = p.GetProvider(pluginType, cp.Id);
102+
var certs = await certManager.GetManagedCertificates(filter);
103+
104+
list.AddRange(certs);
105+
}
106+
catch (Exception ex)
107+
{
108+
_serviceLog?.Error($"Failed to query certificate manager plugin {cp.Title} {ex}");
109+
}
90110
}
91111
}
92112
}
113+
catch (Exception ex)
114+
{
115+
_serviceLog?.Error($"Failed to query certificate manager providers {ex}");
116+
}
93117
}
94118
else
95119
{
96120
_serviceLog?.Error($"Failed to create one or more certificate manager plugins");
97121
}
98122
}
123+
124+
lock (_externallyManagedCertificatesCache)
125+
{
126+
// reset cache
127+
_externallyManagedCertificatesCache = list;
128+
}
99129
}
100130

101-
return externalList;
131+
_externallyManagedCacheUpdated = DateTimeOffset.UtcNow;
132+
133+
return _externallyManagedCertificatesCache;
102134
}
103135

104136
/// <summary>
@@ -152,6 +184,17 @@ public async Task<ManagedCertificateSearchResult> GetManagedCertificateResults(M
152184
summary.AwaitingUser = ms.Count(c => c.Health == ManagedCertificateHealth.AwaitingUser);
153185
summary.NoCertificate = ms.Count(c => c.DateStart == null);
154186

187+
if (_externallyManagedCertificatesCache.Any())
188+
{
189+
summary.ExternallyManaged = _externallyManagedCertificatesCache.Count;
190+
summary.Total += _externallyManagedCertificatesCache.Count;
191+
summary.Healthy += _externallyManagedCertificatesCache.Count(c => c.Health == ManagedCertificateHealth.OK);
192+
summary.Error += _externallyManagedCertificatesCache.Count(c => c.Health == ManagedCertificateHealth.Error);
193+
summary.Warning += _externallyManagedCertificatesCache.Count(c => c.Health == ManagedCertificateHealth.Warning);
194+
summary.AwaitingUser += _externallyManagedCertificatesCache.Count(c => c.Health == ManagedCertificateHealth.AwaitingUser);
195+
summary.NoCertificate += _externallyManagedCertificatesCache.Count(c => c.DateStart == null);
196+
}
197+
155198
// count items with invalid config (e.g. multiple primary domains)
156199
summary.InvalidConfig = ms.Count(c => c.DomainOptions.Count(d => d.IsPrimaryDomain) > 1);
157200

src/Certify.Core/Management/CertifyManager/CertifyManager.ManagementHub.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -463,7 +463,7 @@ public async Task<InstanceCommandResult> PerformHubCommandWithResult(InstanceCom
463463
else if (arg.CommandType == ManagementHubCommands.GetManagedItems)
464464
{
465465
// Get all managed items
466-
var items = await GetManagedCertificates(new ManagedCertificateFilter { });
466+
var items = await GetManagedCertificates(new ManagedCertificateFilter { IncludeExternal = CoreAppSettings.Current.EnableExternalCertManagers });
467467
val = new ManagedInstanceItems { InstanceId = _serverConfig.HubAssignedInstanceId, Items = items };
468468
}
469469
else if (arg.CommandType == ManagementHubCommands.GetStatusSummary)

src/Certify.Models/Hub/ManagedCertificateSummary.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,11 @@ public record ManagedCertificateSummary
6262
/// If true, there is a certificate available (latest successful certificate order)
6363
/// </summary>
6464
public bool HasCertificate { get; set; }
65+
66+
/// <summary>
67+
/// If true, is managed by an external certificate manager (e.g. Certbot, Posh-ACME, etc.)
68+
/// </summary>
69+
public bool IsExternallyManaged { get; set; }
6570
}
6671

6772
public record ManagedCertificateSummaryResult

src/Certify.Models/Providers/ICertificateManager.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,17 @@
44
using Certify.Models;
55
using Certify.Models.Config;
66
using Certify.Models.Providers;
7+
using Microsoft.Extensions.Logging;
78

89
#nullable disable
910

1011
namespace Certify.Providers.CertificateManagers
1112
{
1213
public interface ICertificateManager
1314
{
15+
16+
void Init(ILogger logger, string settingsPath = "", string logPath = "");
17+
1418
Task<bool> IsPresent();
1519

1620
Task<ManagedCertificate> GetManagedCertificate(string id);

src/Certify.Models/Reporting/StatusSummary.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ public class StatusSummary : BindableBase
1212

1313
public int NoCertificate { get; set; }
1414

15+
public int ExternallyManaged { get; set; }
1516
public int TotalDomains { get; set; }
1617
}
1718
}

src/Certify.Server/Certify.Server.Hub.Api/Controllers/internal/HubController.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,15 +89,16 @@ public async Task<IActionResult> GetHubManagedItems(string? instanceId, string?
8989
Id = i.Id ?? "",
9090
Title = $"{i.Name}" ?? "",
9191
OS = instance?.OS,
92-
ClientDetails = instance?.ClientName,
92+
ClientDetails = i.SourceId != null ? i.SourceName : instance?.ClientName,
9393
PrimaryIdentifier = i.GetCertificateIdentifiers().FirstOrDefault(p => p.Value == i.RequestConfig.PrimaryDomain) ?? i.GetCertificateIdentifiers().FirstOrDefault(),
9494
Identifiers = i.GetCertificateIdentifiers(),
9595
DateRenewed = i.DateRenewed,
9696
DateExpiry = i.DateExpiry,
9797
Comments = i.Comments ?? "",
9898
Status = i.Health.ToString(),
9999
DateRetrieved = i.DateRetrieved,
100-
HasCertificate = !string.IsNullOrEmpty(i.CertificatePath)
100+
HasCertificate = !string.IsNullOrEmpty(i.CertificatePath),
101+
IsExternallyManaged = i.ItemType == ManagedCertificateType.SSL_ExternallyManaged
101102
};
102103
}
103104
)

src/Certify.Server/Certify.Server.Hub.Api/Controllers/v1/CertificateController.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System.Net;
22
using System.Text;
33
using Certify.Client;
4+
using Certify.Models;
45
using Certify.Models.Hub;
56
using Certify.Models.Reporting;
67
using Certify.Server.Hub.Api.Services;
@@ -197,7 +198,8 @@ public async Task<IActionResult> GetManagedCertificates(string? keyword, int? pa
197198
DateExpiry = i.DateExpiry,
198199
Comments = i.Comments ?? "",
199200
Status = i.Health.ToString(),
200-
HasCertificate = !string.IsNullOrEmpty(i.CertificatePath)
201+
HasCertificate = !string.IsNullOrEmpty(i.CertificatePath),
202+
IsExternallyManaged = i.ItemType == ManagedCertificateType.SSL_ExternallyManaged
201203
}).OrderBy(a => a.Title);
202204

203205
var result = new ManagedCertificateSummaryResult

0 commit comments

Comments
 (0)