Skip to content

Commit a85aca9

Browse files
authored
Merge 1.1.0 to main
2 parents 12c9cec + 8e4fee0 commit a85aca9

File tree

6 files changed

+84
-20
lines changed

6 files changed

+84
-20
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
- 1.1.0
2+
- Add support for external SANs/subject (not in CSR)
13
- 1.0.0
24
- First production release of the GCP CAS AnyCA Gateway REST plugin that implements:
35
* CA Sync:

GCPCAS/Client/CreateCertificateRequestBuilder.cs

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ limitations under the License.
1616

1717
using System;
1818
using System.Collections.Generic;
19+
using System.Linq;
1920
using System.Text.Json;
2021
using Google.Cloud.Security.PrivateCA.V1;
2122
using Google.Protobuf.WellKnownTypes;
@@ -31,6 +32,8 @@ public class CreateCertificateRequestBuilder : ICreateCertificateRequestBuilder
3132

3233
private string _csrString;
3334
private string _certificateTemplate;
35+
private string _subject;
36+
private List<string> _dnsSans;
3437
private int _certificateLifetimeDays = GCPCASPluginConfig.DefaultCertificateLifetime;
3538

3639
public ICreateCertificateRequestBuilder WithCsr(string csr)
@@ -94,13 +97,30 @@ public ICreateCertificateRequestBuilder WithRequestFormat(RequestFormat requestF
9497

9598
public ICreateCertificateRequestBuilder WithSans(Dictionary<string, string[]> san)
9699
{
97-
if (san != null & san.Count > 0) _logger.LogTrace($"Found non-zero list of SANs - Ignoring and using SANs from CSR");
100+
_dnsSans = new List<string>();
101+
if (san != null & san.Count > 0)
102+
{
103+
var dnsKeys = san.Keys.Where(k => k.Contains("dns", StringComparison.OrdinalIgnoreCase)).ToList();
104+
foreach (var key in dnsKeys)
105+
{
106+
_dnsSans.AddRange(san[key]);
107+
}
108+
_logger.LogTrace($"Found {_dnsSans.Count} SANs");
109+
}
110+
else
111+
{
112+
_logger.LogTrace($"Found no external SANs - Using SANs from CSR");
113+
}
98114
return this;
99115
}
100116

101117
public ICreateCertificateRequestBuilder WithSubject(string subject)
102118
{
103-
if (!string.IsNullOrWhiteSpace(subject)) _logger.LogTrace($"Found non-empty subject {subject} - Ignoring and using CSR value");
119+
if (!string.IsNullOrWhiteSpace(subject))
120+
{
121+
_logger.LogTrace($"Found non-empty subject {subject}");
122+
_subject = subject;
123+
}
104124
return this;
105125
}
106126

@@ -109,10 +129,35 @@ public CreateCertificateRequest Build(string locationId, string projectId, strin
109129
_logger.LogDebug("Constructing CreateCertificateRequest");
110130
CaPoolName caPoolName = new CaPoolName(projectId, locationId, caPool);
111131

132+
CertificateConfig certConfig = new CertificateConfig();
133+
certConfig.SubjectConfig = new CertificateConfig.Types.SubjectConfig();
134+
bool useConfig = false;
135+
if (!string.IsNullOrEmpty(_subject))
136+
{
137+
certConfig.SubjectConfig.Subject = new Subject
138+
{
139+
CommonName = Utilities.ParseSubject(_subject, "CN=", false),
140+
Organization = Utilities.ParseSubject(_subject, "O=", false),
141+
OrganizationalUnit = Utilities.ParseSubject(_subject, "OU=", false),
142+
CountryCode = Utilities.ParseSubject(_subject, "C=", false),
143+
Locality = Utilities.ParseSubject(_subject, "L=", false)
144+
};
145+
useConfig = true;
146+
}
147+
if (_dnsSans.Count > 0)
148+
{
149+
certConfig.SubjectConfig.SubjectAltName = new SubjectAltNames
150+
{
151+
DnsNames = { _dnsSans }
152+
};
153+
useConfig = true;
154+
}
155+
112156
Certificate theCertificate = new Certificate
113157
{
114158
PemCsr = _csrString,
115159
Lifetime = Duration.FromTimeSpan(new TimeSpan(_certificateLifetimeDays, 0, 0, 0)),
160+
Config = (useConfig) ? certConfig : null,
116161
};
117162

118163
if (!string.IsNullOrWhiteSpace(_certificateTemplate))

GCPCAS/Utilities.cs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
7+
namespace Keyfactor.Extensions.CAPlugin.GCPCAS
8+
{
9+
public class Utilities
10+
{
11+
public static string ParseSubject(string subject, string rdn, bool required = true)
12+
{
13+
string escapedSubject = subject.Replace("\\,", "|");
14+
string rdnString = escapedSubject.Split(',').ToList().Where(x => x.Contains(rdn)).FirstOrDefault();
15+
16+
if (!string.IsNullOrEmpty(rdnString))
17+
{
18+
return rdnString.Replace(rdn, "").Replace("|", ",").Trim();
19+
}
20+
else if (required)
21+
{
22+
throw new Exception($"The request is missing a {rdn} value");
23+
}
24+
else
25+
{
26+
return null;
27+
}
28+
}
29+
}
30+
}

README.md

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,9 @@ The [Google Cloud Platform (GCP) CA Services (CAS)](https://cloud.google.com/sec
3939
* CA Sync:
4040
* Download all certificates issued by connected Enterprise tier CAs in GCP CAS (full sync).
4141
* Download all certificates issued by connected Enterprise tier CAs in GCP CAS issued after a specified time (incremental sync).
42-
* Certificate enrollment for all published GoDaddy Certificate SKUs:
42+
* Certificate enrollment for all published GCP Certificate SKUs:
4343
* Support certificate enrollment (new keys/certificate).
44+
* Support auto-enrollment (subject/SANs outside of the CSR)
4445
* Certificate revocation:
4546
* Request revocation of a previously issued certificate.
4647

@@ -154,21 +155,6 @@ Both the Keyfactor Command and AnyCA Gateway REST servers must trust the root CA
154155

155156
3. Follow the [official Keyfactor documentation](https://software.keyfactor.com/Guides/AnyCAGatewayREST/Content/AnyCAGatewayREST/AddCA-Keyfactor.htm) to add each defined Certificate Authority to Keyfactor Command and import the newly defined Certificate Templates.
156157

157-
4. In Keyfactor Command (v12.3+), for each imported Certificate Template, follow the [official documentation](https://software.keyfactor.com/Core-OnPrem/Current/Content/ReferenceGuide/Configuring%20Template%20Options.htm) to define enrollment fields for each of the following parameters:
158-
159-
* **CertificateLifetimeDays** - The desired lifetime, in days, of the issued certificate. Used by GCP to create the `not_before_time` and `not_after_time` fields in the signed X.509 certificate. If the lifetime extends past the life of any CA in the issuing chain, this value will be truncated. Additionally, if the lifetime extends past the CA Pool's Maximum Lifetime, this value will be truncated accordingly. The default value is 365 days.
160-
161-
162-
## Plugin Mechanics
163-
### Enrollment/Renewal/Reissuance
164-
165-
The GCP CAS AnyCA Gateway REST plugin treats _all_ certificate enrollment as a new enrollment.
166-
167-
### Synchronization
168-
169-
The GCP CAS AnyCA Gateway REST plugin uses the [`ListCertificatesRequest` RPC](https://cloud.google.com/certificate-authority-service/docs/reference/rpc/google.cloud.security.privateca.v1#google.cloud.security.privateca.v1.ListCertificatesRequest) when synchronizing certificates from GCP. At the time the latest release, this RPC does not enable granularity to list certificates issued by a particular CA. As such, the CA Synchronization job implemented by the plugin will _always_ download all certificates issued by _any CA_ in the CA Pool.
170-
171-
> Friendly reminder to always follow the [GCP CAS best practices](https://cloud.google.com/certificate-authority-service/docs/best-practices)
172158

173159

174160
## License

docsource/configuration.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@ The [Google Cloud Platform (GCP) CA Services (CAS)](https://cloud.google.com/sec
55
* CA Sync:
66
* Download all certificates issued by connected Enterprise tier CAs in GCP CAS (full sync).
77
* Download all certificates issued by connected Enterprise tier CAs in GCP CAS issued after a specified time (incremental sync).
8-
* Certificate enrollment for all published GoDaddy Certificate SKUs:
8+
* Certificate enrollment for all published GCP Certificate SKUs:
99
* Support certificate enrollment (new keys/certificate).
10+
* Support auto-enrollment (subject/SANs outside of the CSR)
1011
* Certificate revocation:
1112
* Request revocation of a previously issued certificate.
1213

integration-manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,4 @@
4141
]
4242
}
4343
}
44-
}
44+
}

0 commit comments

Comments
 (0)