diff --git a/.github/workflows/keyfactor-bootstrap-workflow.yml b/.github/workflows/keyfactor-bootstrap-workflow.yml
new file mode 100644
index 0000000..2c1c440
--- /dev/null
+++ b/.github/workflows/keyfactor-bootstrap-workflow.yml
@@ -0,0 +1,20 @@
+name: Keyfactor Bootstrap Workflow
+
+on:
+ workflow_dispatch:
+ pull_request:
+ types: [opened, closed, synchronize, edited, reopened]
+ push:
+ create:
+ branches:
+ - 'release-*.*'
+
+jobs:
+ call-starter-workflow:
+ uses: keyfactor/actions/.github/workflows/starter.yml@v3
+ 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 }}
\ No newline at end of file
diff --git a/.github/workflows/keyfactor-starter-workflow.yml b/.github/workflows/keyfactor-starter-workflow.yml
deleted file mode 100644
index 8d265c6..0000000
--- a/.github/workflows/keyfactor-starter-workflow.yml
+++ /dev/null
@@ -1,42 +0,0 @@
-name: Starter Workflow
-on: [workflow_dispatch, push, pull_request]
-
-jobs:
- call-create-github-release-workflow:
- uses: Keyfactor/actions/.github/workflows/github-release.yml@main
-
- get-manifest-properties:
- runs-on: windows-latest
- outputs:
- update_catalog: ${{ steps.read-json.outputs.prop }}
- steps:
- - uses: actions/checkout@v3
- - name: Read json
- id: read-json
- shell: pwsh
- run: |
- $json = Get-Content integration-manifest.json | ConvertFrom-Json
- echo "::set-output name=prop::$(echo $json.update_catalog)"
-
- call-dotnet-build-and-release-workflow:
- needs: [call-create-github-release-workflow]
- uses: Keyfactor/actions/.github/workflows/dotnet-build-and-release.yml@main
- with:
- release_version: ${{ needs.call-create-github-release-workflow.outputs.release_version }}
- release_url: ${{ needs.call-create-github-release-workflow.outputs.release_url }}
- release_dir: src/GoogleCAProxy/bin/Release
- secrets:
- token: ${{ secrets.PRIVATE_PACKAGE_ACCESS }}
-
- call-generate-readme-workflow:
- if: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
- uses: Keyfactor/actions/.github/workflows/generate-readme.yml@main
- secrets:
- token: ${{ secrets.APPROVE_README_PUSH }}
-
- call-update-catalog-workflow:
- needs: get-manifest-properties
- if: needs.get-manifest-properties.outputs.update_catalog == 'True' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch')
- uses: Keyfactor/actions/.github/workflows/update-catalog.yml@main
- secrets:
- token: ${{ secrets.SDK_SYNC_PAT }}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 36d6511..38be5c7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,20 @@
-# CHANGELOG
-v1.1
+# v2.1.0
+* Support external SANs/subject (not in CSR)
+* Change Certificate ID on enrollment to use a GUID for uniqueness
+
+ # v2.0.1
+* Set `grpc.max_receive_message_length` to -1 on `CertificateAuthorityServiceClientBuilder`
+
+# v2.0.0
+* Migrate `packages.config` to `PackageReference` format
+* Upgrade packages to support Keyfactor AnyCA Gateway DCOM v24.2
+ * Upgrade `Keyfactor.AnyGateway.SDK` to `24.2.0-PRERELEASE-47446`
+* Add support for [GCP CAS Certificate Templates](https://cloud.google.com/certificate-authority-service/docs/policy-controls)
+* Enable configuration of CA Pool-based or CA-specific certificate enrollment. If the `CAId` is specified, certificates are enrolled with the CA specified by `CAId`. Otherwise, GCP CAS selects a CA in the CA Pool based on policy.
+
+# v1.1.0
- Remove template references from README
- Small bug fixes
-v1.0 Initial Release. Support for Google GA CA Service. Sync, Enroll, and Revocation.
+# v1.0.0
+* Initial Release. Support for Google GA CA Service. Sync, Enroll, and Revocation.
diff --git a/README.md b/README.md
index 9a2cdc7..37012db 100644
--- a/README.md
+++ b/README.md
@@ -1,170 +1,219 @@
-# Google Cloud CA
+
+ GCP CAS AnyCA Gateway DCOM plugin
+
-The Google Cloud Gateway enables the following certificate authority management functions via Keyfactor Command: PFX & CSR Enrollment, Revocation, and Synchronization (Full & Incremental)
+
+
+
+
+
+
+
-#### Integration status: Production - Ready for use in production environments.
+
+
+
+ Support
+
+ ·
+
+ License
+
+ ·
+
+ Related Integrations
+
+
-## About the Keyfactor AnyGateway CA Connector
+## Support
+The GCP CAS AnyCA Gateway DCOM plugin is open source and there is **no SLA**. Keyfactor will address issues as resources become available. Keyfactor customers may request escalation by opening up a support ticket through their Keyfactor representative.
-This repository contains an AnyGateway CA Connector, which is a plugin to the Keyfactor AnyGateway. AnyGateway CA Connectors allow Keyfactor Command to be used for inventory, issuance, and revocation of certificates from a third-party certificate authority.
+> To report a problem or suggest a new feature, use the **[Issues](../../issues)** tab. If you want to contribute actual bug fixes or proposed enhancements, use the **[Pull requests](../../pulls)** tab.
+## Compatibility
+This AnyGateway is designed to be used with version 24.2 of the Keyfactor AnyCA Gateway DCOM Framework.
+## Requirements
-***
+### Application Default Credentials
-# Notes
-See the Google website for details on the [Google Certificate Authority Service](https://cloud.google.com/certificate-authority-service)
+The GCP CAS AnyCA Gateway DCOM plugin connects to and authenticates with GCP CAS implicitly using [Application Default Credentials](https://cloud.google.com/docs/authentication/application-default-credentials). This means that all authentication-related configuration of the GCP CAS AnyCA Gateway REST plugin is implied by the environment where the AnyCA Gateway REST itself is running.
-It should be noted that currently, due to the design of the DevOps tier of CA, Enterprise tier CAs are only supported by the AnyGateway.
+Please refer to [Google's documentation](https://cloud.google.com/docs/authentication/provide-credentials-adc) to configure ADC on the server running the AnyCA Gateway REST.
-# Compatibility
-This AnyGateway is designed to be used with version 21.3.2 of the Keyfactor AnyGateway Framework
+> The easiest way to configure ADC for non-production environments is to use [User Credentials](https://cloud.google.com/docs/authentication/provide-credentials-adc#local-dev).
+>
+> For production environments that use an ADC method requiring the `GOOGLE_APPLICATION_CREDENTIALS` environment variable, you must ensure the following:
+>
+> 1. The service account that the AnyCA Gateway REST runs under must have read permission to the GCP credential JSON file.
+> 2. You must set the `GOOGLE_APPLICATION_CREDENTIALS` environment variable for the Windows Service running the AnyCA Gateway REST using the [Windows registry editor](https://learn.microsoft.com/en-us/troubleshoot/windows-server/performance/windows-registry-advanced-users).
+ > * Refer to the [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment](https://learn.microsoft.com/en-us/windows/win32/procthread/environment-variables) docs.
-# Prerequisites
-## [Authentication](https://cloud.google.com/docs/authentication/production)
-A JSON file generated for a Google Service Account will need to be created and placed on the AnyGateway Server.
-The path of this file into the GOOGLE_APPLICATION_CREDENTIALS environment variable to be used during a CA session.
-Since the AnyGateway is required to run as the Network Service account, the registry will need to be modified to provide the service access to the Environment variable above.
-The GOOGLE_APPLICATION_CREDENTIALS variable should be placed in the following registry location and read access provided:
+If the selected ADC mechanism is [Service Account Key](https://cloud.google.com/docs/authentication/provide-credentials-adc#wlif-key), it's recommended that a [custom role is created](https://cloud.google.com/iam/docs/creating-custom-roles) that has the following minimum permissions:
-* HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment
+* `privateca.certificateTemplates.list`
+* `privateca.certificateTemplates.use`
+* `privateca.certificateAuthorities.get`
+* `privateca.certificates.create`
+* `privateca.certificates.get`
+* `privateca.certificates.list`
+* `privateca.certificates.update`
+* `privateca.caPools.get`
-## [Authorization](https://cloud.google.com/certificate-authority-service/docs/reference/permissions-and-roles)
-Currently the only method supported for authentication is a Service Credential with the following IAM authorizations. Any built in role with the below authorizations will function as well.
-* privateca.caPools.list
-* privateca.caPools.get
-* privateca.certificateTemplates.list
-* privateca.certificateTemplates.get
-* privateca.certificateTemplates.use
-* privateca.certificateAuthorities.list
-* privateca.certificateAuthorities.get
-* privateca.certificates.create
-* privateca.certificates.get
-* privateca.certificates.list
-* privateca.certificates.update
-* privateca.reusableConfigs.get
-* privateca.reusableConfigs.list
-* resourcemanager.projects.get
+> The built-in CA Service Operation Manager `roles/privateca.caManager` role can also be used, but is more permissive than a custom role with the above permissions.
-## Certificate Chain
-In order to enroll for certificates the Keyfactor Command server must trust the Private CA chain. Once you create your Root and/or Subordinate CA, make sure to import the certificate chain into the Command Server certificate store
+### Root CA Configuration
-# Install
-* Install the AnyCA Gateway Framework using the MSI from the Software Download Portal
+Both the Keyfactor Command and AnyCA Gateway DCOM servers must trust the root CA, and if applicable, any subordinate CAs for all features to work as intended. Download the CA Certificate (and chain, if applicable) from GCP [CAS](https://console.cloud.google.com/security/cas), and import them into the appropriate certificate store on the AnyCA Gateway DCOM server.
-* Download latest successful build from [GitHub](https://github.com/Keyfactor/google-cloud-cagateway)
+* **Windows** - The root CA and applicable subordinate CAs must be imported into the Windows certificate store. The certificates can be imported using the Microsoft Management Console (MMC) or PowerShell.
+ * Certificates can be imported in MMC by "File" -> "Add/Remove Snap-in" -> "Certificates" -> "Add >" -> "Computer account" -> "Local computer".
+ * Root CAs must go in the `Trusted Root Certification Authorities` certificate store.
+ * Subordinate CAs must go in the `Intermediate Certification Authorities` certificate store.
-* Copy *.dll to the Program Files\Keyfactor\ Keyfactor AnyGateway directory
+> If the Root CA and chain are not known by the server hosting the AnyCA Gateway DCOM, the certificate chain _may not_ be returned to Command in certificate enrollment requests.
-* Update the CAProxyServer.config file
- * Update the CAConnection section to point at the GoogleCAProxy class
- ```xml
-
- ```
- * Depending on the version of the AnyCA Gateway installed, additional binding redirects may need to be applied from the app.config. These redirections will be added to the CAProxyServer.config file
+### Template Identification
-# Configuration
-The following sections will breakdown the required configurations for the AnyGatewayConfig.json file that will be imported to configure the Google CA.
+The GCP CAS AnyCA Gateway DCOM plugin supports [GCP CAS Certificate Templates](https://cloud.google.com/certificate-authority-service/docs/policy-controls). Certificate Templates exist at the Project level in GCP. Before installing the plugin, identify the [Certificate Templates](https://console.cloud.google.com/security/cas) that you want to make available to Keyfactor Command and [create Certificate Templates in AD](https://software.keyfactor.com/Guides/AnyGateway_Generic/Content/AnyGateway/Preparing_Templates.htm).
-## Templates
-The Google CA has introduced the concept of Templates for the V1 release.
-The product ID mapped below must be the Template Name from the cloud console.
-The API does not provide certificate lifetime information, but any value can be placed here.
-If the value is over the configured value, the Google CA will set to the maximum value as determined by the template configuration.
- ```json
- "Templates": {
- "GoogleCAWebServer": {
- "ProductID": "", /*Value not used, so set to empty string. 'ProductID' element must be present.*/
- "Parameters": {
- "Lifetime": "300",/*days*/
- }
+> Certificate Templates in GCP are not required. The plugin will not specify a template for the [CreateCertificate RPC](https://cloud.google.com/certificate-authority-service/docs/reference/rpc/google.cloud.security.privateca.v1#google.cloud.security.privateca.v1.CertificateAuthorityService.CreateCertificate) if the `ProductId` (discussed later) is set to `Default`.
+
+## Installation
+
+1. Install AnyCA Gateway DCOM v24.2 per the [official Keyfactor documentation](https://software.keyfactor.com/Guides/AnyGateway_Generic/Content/AnyGateway/Introduction.htm).
+
+2. Download the [latest GCP CAS AnyCA Gateway DCOM plugin assemblies](https://github.com/Keyfactor/gcp-cloud-cagateway/releases/latest).
+
+3. Copy `*.dll` to the `C:\Program Files\Keyfactor\Keyfactor AnyGateway` directory.
+
+4. Update the `CAProxyServer.config` file.
+ 1. Update the `$.configuration.unity.CAConnector` section to point at the `GoogleCAProxy` class.
+
+ ```xml
+
+ ```
+
+ 2. Modify the `Newtonsoft.Json` `bindingRedirect` to redirect versions from `0.0.0.0-13.0.0.0` to `12.0.0.0`.
+
+ ```xml
+
+
+
+
+ ```
+
+ 3. Add a `bindingRedirect` for `Google.Apis.Auth` to redirect versions from `0.0.0.0-1.67.0.0` to `1.67.0.0`.
+
+ ```xml
+
+
+
+
+ ```
+
+ 4. Add a `bindingRedirect` for `System.Memory` to redirect versions from `0.0.0.0-4.0.1.2` to `4.0.1.1`.
+
+ ```xml
+
+
+
+
+ ```
+
+ > Depending on additional environment-specific factors, additional binding redirects may need to be applied to `CAProxyServer.config`.
+
+## Configuration
+The following sections will breakdown the required configurations for the AnyGatewayConfig.json file that will be imported to configure the Google CA.
+
+### Templates
+
+As discussed in the [Template Identification](#template-identification), the GCP CAS AnyCA Gateway DCOM plugin supports [GCP CAS Certificate Templates](https://cloud.google.com/certificate-authority-service/docs/policy-controls). The Keyfactor AnyCA Gateway DCOM maps [AD Certificate Templates](https://learn.microsoft.com/en-us/windows-server/identity/ad-cs/certificate-template-concepts) to GCP Certificate Templates via the `ProductID` property in the `Templates` section of configuration files.
+
+_At least one_ Certificate Template must be defined in this section with the `ProductID` set to `Default`. This Product ID corresponds to no Certificate Template for the [CreateCertificate RPC](https://cloud.google.com/certificate-authority-service/docs/reference/rpc/google.cloud.security.privateca.v1#google.cloud.security.privateca.v1.CertificateAuthorityService.CreateCertificate).
+
+Subsequent Certificate Templates should set the `ProductID` to the Certificate Template ID in GCP CAS.
+
+```json
+"Templates": {
+ "GCPCASDefault": {
+ "ProductID": "Default",
+ "Parameters": {
+ "Lifetime": "300", /* Certificate validity in days */
+ }
}
}
- ```
+```
+
+> The `Lifetime` key should be added as a Custom Enrollment Parameter/Field for each Certificate Template in Keyfactor Command per the [official Keyfactor documentation](https://software.keyfactor.com/Core-OnPrem/Current/Content/ReferenceGuide/Configuring%20Template%20Options.htm).
+
## Security
-The security section does not change specifically for the Google CA. Refer to the Keyfactor AnyGateway Documentation for more detail
+
+Refer to the [official Keyfactor documentation](https://software.keyfactor.com/Guides/AnyGateway_Generic/Content/AnyGateway/cmdlets.htm) to configure the `Security` section. The following is provided as an example.
+
```json
- /*Grant permissions on the CA to users or groups in the local domain.
- READ: Enumerate and read contents of certificates.
- ENROLL: Request certificates from the CA.
- OFFICER: Perform certificate functions such as issuance and revocation. This is equivalent to "Issue and Manage" permission on the Microsoft CA.
- ADMINISTRATOR: Configure/reconfigure the gateway.
- Valid permission settings are "Allow", "None", and "Deny".*/
- "Security": {
- "Keyfactor\\Administrator": {
- "READ": "Allow",
- "ENROLL": "Allow",
- "OFFICER": "Allow",
- "ADMINISTRATOR": "Allow"
- },
- "Keyfactor\\gateway_test": {
- "READ": "Allow",
- "ENROLL": "Allow",
- "OFFICER": "Allow",
- "ADMINISTRATOR": "Allow"
- },
- "Keyfactor\\SVC_TimerService": {
- "READ": "Allow",
- "ENROLL": "Allow",
- "OFFICER": "Allow",
- "ADMINISTRATOR": "None"
- },
- "Keyfactor\\SVC_AppPool": {
- "READ": "Allow",
+/* Grant permissions on the CA to users or groups in the local domain.
+ READ: Enumerate and read contents of certificates.
+ ENROLL: Request certificates from the CA.
+ OFFICER: Perform certificate functions such as issuance and revocation. This is equivalent to "Issue and Manage" permission on the Microsoft CA.
+ ADMINISTRATOR: Configure/reconfigure the gateway.
+
+ Valid permission settings are "Allow", "None", and "Deny".
+*/
+"Security": {
+ "Keyfactor\\Administrator": {
+ "READ": "Allow",
"ENROLL": "Allow",
"OFFICER": "Allow",
"ADMINISTRATOR": "Allow"
- }
+ },
+ "Keyfactor\\gateway_test": {
+ "READ": "Allow",
+ "ENROLL": "Allow",
+ "OFFICER": "Allow",
+ "ADMINISTRATOR": "Allow"
+ },
+ "Keyfactor\\SVC_TimerService": {
+ "READ": "Allow",
+ "ENROLL": "Allow",
+ "OFFICER": "Allow",
+ "ADMINISTRATOR": "None"
+ },
+ "Keyfactor\\SVC_AppPool": {
+ "READ": "Allow",
+ "ENROLL": "Allow",
+ "OFFICER": "Allow",
+ "ADMINISTRATOR": "Allow"
}
+}
```
-## CerificateManagers
-The Certificate Managers section is optional.
- If configured, all users or groups granted OFFICER permissions under the Security section
- must be configured for at least one Template and one Requester.
- Uses "" to specify all templates. Uses "Everyone" to specify all requesters.
- Valid permission values are "Allow" and "Deny".
-```json
- "CertificateManagers":{
- "DOMAIN\\Username":{
- "Templates":{
- "MyTemplateShortName":{
- "Requesters":{
- "Everyone":"Allow",
- "DOMAIN\\Groupname":"Deny"
- }
- },
- "":{
- "Requesters":{
- "Everyone":"Allow"
- }
- }
- }
- }
- }
-```
+
## CAConnection
-The CA Connection section will determine which CA in the Google cloud is integrated with Keyfactor. There are 3 required configuration fields
-* ProjectId
-This is the Resource ID of the project that contains the Google CA Service
-* LocationId
-This is the resource ID of the geographical location (i.e. us-east1) within the Google Cloud
-* CAId
-This is the resource Id of any one of the CAs created in the CA pool using the [Google Cloud Console](https://console.cloud.google.com)
-* CAPoolId
-This is the resource id of the CA Pool created using the [Google Cloud Console](https://console.cloud.google.com)
+
+The `CAConnection` section selects the GCP Project/CA Pool/CA whose certificate operations will be extended to Keyfactor. There are three required fields.
+
+* `ProjectId` - The Resource ID of the project that contains the Google CA Service.
+* `LocationId` - The GCP location ID where the project containing the target GCP CAS CA is located. For example, 'us-central1'.
+* `CAPoolId` - The CA Pool ID in GCP CAS to use for certificate operations. If the CA Pool has resource name `projects/my-project/locations/us-central1/caPools/my-pool`, this field should be set to `my-pool`.
+* `CAId` (optional) - The CA ID of a CA in the same CA Pool as CAPool. For example, to issue certificates from a CA with resource name `projects/my-project/locations/us-central1/caPools/my-pool/certificateAuthorities/my-ca`, this field should be set to `my-ca`.
```json
"CAConnection": {
- "ProjectId": "concise-frame-296019",
"LocationId": "us-east1",
- "CAId":"ca-enterprise-subordinate-sandbox-tls",
- "CAPoolId":"gcp-test-pool"
+ "ProjectId": "concise-frame-296019",
+ "CAPoolId":"gcp-test-pool",
+ "CAId":"ca-enterprise-subordinate-sandbox-tls"
}
```
+
+> If `CAId` is not specified, CA selection will defer to GCP CAS - a CA in the CA Pool identified by `CAPoolId` will be selected automatically.
+
## GatewayRegistration
+
There are no Google Specific Changes for the GatewayRegistration section. Refer to the Keyfactor AnyGateway Documentation for more detail on required changed to support the AnyCA Gateway
+
```json
"GatewayRegistration": {
"LogicalName": "GoogleCASandbox",
@@ -177,7 +226,9 @@ There are no Google Specific Changes for the GatewayRegistration section. Refer
```
## ServiceSettings
+
There are no Google Specific Changes for the GatewayRegistration section. Refer to the Keyfactor AnyGateway Documentation for more detail on required changed to support the AnyCA Gateway
+
```json
"ServiceSettings": {
"ViewIdleMinutes": 8,
@@ -186,3 +237,12 @@ There are no Google Specific Changes for the GatewayRegistration section. Refer
}
```
+
+
+## License
+
+Apache License 2.0, see [LICENSE](LICENSE).
+
+## Related Integrations
+
+See all [Keyfactor integrations](https://github.com/topics/keyfactor-integration).
\ No newline at end of file
diff --git a/docsource/content.md b/docsource/content.md
new file mode 100644
index 0000000..0a5c55b
--- /dev/null
+++ b/docsource/content.md
@@ -0,0 +1,222 @@
+## Overview
+
+The [Google Cloud Platform (GCP) CA Services (CAS)](https://cloud.google.com/security/products/certificate-authority-service) AnyCA Gateway DCOM plugin extends the capabilities of connected GCP CAS CAs to [Keyfactor Command](https://www.keyfactor.com/products/command/) via the Keyfactor AnyCA Gateway DCOM. The plugin represents a fully featured AnyCA DCOM Plugin with the following capabilies:
+
+* CA Sync:
+ * Download all certificates issued by connected Enterprise tier CAs in GCP CAS (full sync).
+ * Download all certificates issued by connected Enterprise tier CAs in GCP CAS issued after a specified time (incremental sync).
+* Certificate enrollment for all published GoDaddy Certificate SKUs:
+ * Support certificate enrollment (new keys/certificate).
+ * Support auto-enrollment (subject/SANs supplied outside of CSR)
+* Certificate revocation:
+ * Request revocation of a previously issued certificate.
+
+> The GCP CAS AnyCA Gateway DCOM plugin is **not** supported for [DevOps Tier](https://cloud.google.com/certificate-authority-service/docs/tiers) Certificate Authority Pools.
+>
+> DevOps tier CA Pools don't offer listing, describing, or revoking certificates.
+
+## Compatibility
+
+This AnyGateway is designed to be used with version 24.2 of the Keyfactor AnyCA Gateway DCOM Framework.
+
+## Requirements
+
+### Application Default Credentials
+
+The GCP CAS AnyCA Gateway DCOM plugin connects to and authenticates with GCP CAS implicitly using [Application Default Credentials](https://cloud.google.com/docs/authentication/application-default-credentials). This means that all authentication-related configuration of the GCP CAS AnyCA Gateway REST plugin is implied by the environment where the AnyCA Gateway REST itself is running.
+
+Please refer to [Google's documentation](https://cloud.google.com/docs/authentication/provide-credentials-adc) to configure ADC on the server running the AnyCA Gateway REST.
+
+> The easiest way to configure ADC for non-production environments is to use [User Credentials](https://cloud.google.com/docs/authentication/provide-credentials-adc#local-dev).
+>
+> For production environments that use an ADC method requiring the `GOOGLE_APPLICATION_CREDENTIALS` environment variable, you must ensure the following:
+>
+> 1. The service account that the AnyCA Gateway REST runs under must have read permission to the GCP credential JSON file.
+> 2. You must set the `GOOGLE_APPLICATION_CREDENTIALS` environment variable for the Windows Service running the AnyCA Gateway REST using the [Windows registry editor](https://learn.microsoft.com/en-us/troubleshoot/windows-server/performance/windows-registry-advanced-users).
+ > * Refer to the [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment](https://learn.microsoft.com/en-us/windows/win32/procthread/environment-variables) docs.
+
+If the selected ADC mechanism is [Service Account Key](https://cloud.google.com/docs/authentication/provide-credentials-adc#wlif-key), it's recommended that a [custom role is created](https://cloud.google.com/iam/docs/creating-custom-roles) that has the following minimum permissions:
+
+* `privateca.certificateTemplates.list`
+* `privateca.certificateTemplates.use`
+* `privateca.certificateAuthorities.get`
+* `privateca.certificates.create`
+* `privateca.certificates.get`
+* `privateca.certificates.list`
+* `privateca.certificates.update`
+* `privateca.caPools.get`
+
+> The built-in CA Service Operation Manager `roles/privateca.caManager` role can also be used, but is more permissive than a custom role with the above permissions.
+
+### Root CA Configuration
+
+Both the Keyfactor Command and AnyCA Gateway DCOM servers must trust the root CA, and if applicable, any subordinate CAs for all features to work as intended. Download the CA Certificate (and chain, if applicable) from GCP [CAS](https://console.cloud.google.com/security/cas), and import them into the appropriate certificate store on the AnyCA Gateway DCOM server.
+
+* **Windows** - The root CA and applicable subordinate CAs must be imported into the Windows certificate store. The certificates can be imported using the Microsoft Management Console (MMC) or PowerShell.
+ * Certificates can be imported in MMC by "File" -> "Add/Remove Snap-in" -> "Certificates" -> "Add >" -> "Computer account" -> "Local computer".
+ * Root CAs must go in the `Trusted Root Certification Authorities` certificate store.
+ * Subordinate CAs must go in the `Intermediate Certification Authorities` certificate store.
+
+> If the Root CA and chain are not known by the server hosting the AnyCA Gateway DCOM, the certificate chain _may not_ be returned to Command in certificate enrollment requests.
+
+### Template Identification
+
+The GCP CAS AnyCA Gateway DCOM plugin supports [GCP CAS Certificate Templates](https://cloud.google.com/certificate-authority-service/docs/policy-controls). Certificate Templates exist at the Project level in GCP. Before installing the plugin, identify the [Certificate Templates](https://console.cloud.google.com/security/cas) that you want to make available to Keyfactor Command and [create Certificate Templates in AD](https://software.keyfactor.com/Guides/AnyGateway_Generic/Content/AnyGateway/Preparing_Templates.htm).
+
+> Certificate Templates in GCP are not required. The plugin will not specify a template for the [CreateCertificate RPC](https://cloud.google.com/certificate-authority-service/docs/reference/rpc/google.cloud.security.privateca.v1#google.cloud.security.privateca.v1.CertificateAuthorityService.CreateCertificate) if the `ProductId` (discussed later) is set to `Default`.
+
+## Installation
+
+1. Install AnyCA Gateway DCOM v24.2 per the [official Keyfactor documentation](https://software.keyfactor.com/Guides/AnyGateway_Generic/Content/AnyGateway/Introduction.htm).
+
+2. Download the [latest GCP CAS AnyCA Gateway DCOM plugin assemblies](https://github.com/Keyfactor/gcp-cloud-cagateway/releases/latest).
+
+3. Copy `*.dll` to the `C:\Program Files\Keyfactor\Keyfactor AnyGateway` directory.
+
+4. Update the `CAProxyServer.config` file.
+ 1. Update the `$.configuration.unity.CAConnector` section to point at the `GoogleCAProxy` class.
+
+ ```xml
+
+ ```
+
+ 2. Modify the `Newtonsoft.Json` `bindingRedirect` to redirect versions from `0.0.0.0-13.0.0.0` to `12.0.0.0`.
+
+ ```xml
+
+
+
+
+ ```
+
+ 3. Add a `bindingRedirect` for `Google.Apis.Auth` to redirect versions from `0.0.0.0-1.67.0.0` to `1.67.0.0`.
+
+ ```xml
+
+
+
+
+ ```
+
+ 4. Add a `bindingRedirect` for `System.Memory` to redirect versions from `0.0.0.0-4.0.1.2` to `4.0.1.1`.
+
+ ```xml
+
+
+
+
+ ```
+
+ > Depending on additional environment-specific factors, additional binding redirects may need to be applied to `CAProxyServer.config`.
+
+## Configuration
+The following sections will breakdown the required configurations for the AnyGatewayConfig.json file that will be imported to configure the Google CA.
+
+### Templates
+
+As discussed in the [Template Identification](#template-identification), the GCP CAS AnyCA Gateway DCOM plugin supports [GCP CAS Certificate Templates](https://cloud.google.com/certificate-authority-service/docs/policy-controls). The Keyfactor AnyCA Gateway DCOM maps [AD Certificate Templates](https://learn.microsoft.com/en-us/windows-server/identity/ad-cs/certificate-template-concepts) to GCP Certificate Templates via the `ProductID` property in the `Templates` section of configuration files.
+
+_At least one_ Certificate Template must be defined in this section with the `ProductID` set to `Default`. This Product ID corresponds to no Certificate Template for the [CreateCertificate RPC](https://cloud.google.com/certificate-authority-service/docs/reference/rpc/google.cloud.security.privateca.v1#google.cloud.security.privateca.v1.CertificateAuthorityService.CreateCertificate).
+
+Subsequent Certificate Templates should set the `ProductID` to the Certificate Template ID in GCP CAS.
+
+```json
+"Templates": {
+ "GCPCASDefault": {
+ "ProductID": "Default",
+ "Parameters": {
+ "Lifetime": "300", /* Certificate validity in days */
+ }
+ }
+}
+```
+
+> The `Lifetime` key should be added as a Custom Enrollment Parameter/Field for each Certificate Template in Keyfactor Command per the [official Keyfactor documentation](https://software.keyfactor.com/Core-OnPrem/Current/Content/ReferenceGuide/Configuring%20Template%20Options.htm).
+
+## Security
+
+Refer to the [official Keyfactor documentation](https://software.keyfactor.com/Guides/AnyGateway_Generic/Content/AnyGateway/cmdlets.htm) to configure the `Security` section. The following is provided as an example.
+
+```json
+/* Grant permissions on the CA to users or groups in the local domain.
+ READ: Enumerate and read contents of certificates.
+ ENROLL: Request certificates from the CA.
+ OFFICER: Perform certificate functions such as issuance and revocation. This is equivalent to "Issue and Manage" permission on the Microsoft CA.
+ ADMINISTRATOR: Configure/reconfigure the gateway.
+
+ Valid permission settings are "Allow", "None", and "Deny".
+*/
+"Security": {
+ "Keyfactor\\Administrator": {
+ "READ": "Allow",
+ "ENROLL": "Allow",
+ "OFFICER": "Allow",
+ "ADMINISTRATOR": "Allow"
+ },
+ "Keyfactor\\gateway_test": {
+ "READ": "Allow",
+ "ENROLL": "Allow",
+ "OFFICER": "Allow",
+ "ADMINISTRATOR": "Allow"
+ },
+ "Keyfactor\\SVC_TimerService": {
+ "READ": "Allow",
+ "ENROLL": "Allow",
+ "OFFICER": "Allow",
+ "ADMINISTRATOR": "None"
+ },
+ "Keyfactor\\SVC_AppPool": {
+ "READ": "Allow",
+ "ENROLL": "Allow",
+ "OFFICER": "Allow",
+ "ADMINISTRATOR": "Allow"
+ }
+}
+```
+
+## CAConnection
+
+The `CAConnection` section selects the GCP Project/CA Pool/CA whose certificate operations will be extended to Keyfactor. There are three required fields.
+
+* `ProjectId` - The Resource ID of the project that contains the Google CA Service.
+* `LocationId` - The GCP location ID where the project containing the target GCP CAS CA is located. For example, 'us-central1'.
+* `CAPoolId` - The CA Pool ID in GCP CAS to use for certificate operations. If the CA Pool has resource name `projects/my-project/locations/us-central1/caPools/my-pool`, this field should be set to `my-pool`.
+* `CAId` (optional) - The CA ID of a CA in the same CA Pool as CAPool. For example, to issue certificates from a CA with resource name `projects/my-project/locations/us-central1/caPools/my-pool/certificateAuthorities/my-ca`, this field should be set to `my-ca`.
+
+```json
+"CAConnection": {
+ "LocationId": "us-east1",
+ "ProjectId": "concise-frame-296019",
+ "CAPoolId":"gcp-test-pool",
+ "CAId":"ca-enterprise-subordinate-sandbox-tls"
+}
+```
+
+> If `CAId` is not specified, CA selection will defer to GCP CAS - a CA in the CA Pool identified by `CAPoolId` will be selected automatically.
+
+## GatewayRegistration
+
+There are no Google Specific Changes for the GatewayRegistration section. Refer to the Keyfactor AnyGateway Documentation for more detail on required changed to support the AnyCA Gateway
+
+```json
+ "GatewayRegistration": {
+ "LogicalName": "GoogleCASandbox",
+ "GatewayCertificate": {
+ "StoreName": "CA",
+ "StoreLocation": "LocalMachine",
+ "Thumbprint": "bc6d6b168ce5c08a690c15e03be596bbaa095ebf"
+ }
+ }
+```
+
+## ServiceSettings
+
+There are no Google Specific Changes for the GatewayRegistration section. Refer to the Keyfactor AnyGateway Documentation for more detail on required changed to support the AnyCA Gateway
+
+```json
+ "ServiceSettings": {
+ "ViewIdleMinutes": 8,
+ "FullScanPeriodHours": 1,
+ "PartialScanPeriodMinutes": 60
+ }
+```
diff --git a/integration-manifest.json b/integration-manifest.json
index 17cd201..4cd0beb 100644
--- a/integration-manifest.json
+++ b/integration-manifest.json
@@ -1,9 +1,11 @@
{
- "$schema": "https://keyfactor.github.io/integration-manifest-schema.json",
- "integration_type": "ca-gateway",
- "name": "Google Cloud CA",
- "status": "production",
- "description": "The Google Cloud Gateway enables the following certificate authority management functions via Keyfactor Command: PFX & CSR Enrollment, Revocation, and Synchronization (Full & Incremental)",
- "link_github": true,
- "update_catalog": true
-}
\ No newline at end of file
+ "$schema": "https://keyfactor.github.io/v2/integration-manifest-schema.json",
+ "integration_type": "ca-gateway",
+ "name": "GCP CAS AnyCA Gateway DCOM plugin",
+ "status": "production",
+ "description": "AnyCA Gateway DCOM plugin that extends Google Cloud Platform Certificate Authority Service to Keyfactor Command",
+ "link_github": true,
+ "update_catalog": true,
+ "support_level": "kf-community",
+ "release_dir": "src\\GoogleCAProxy\\bin\\Release"
+}
diff --git a/readme_source.md b/readme_source.md
deleted file mode 100644
index 357fdaf..0000000
--- a/readme_source.md
+++ /dev/null
@@ -1,173 +0,0 @@
-***
-
-# Notes
-See the Google website for details on the [Google Certificate Authority Service](https://cloud.google.com/certificate-authority-service)
-
-It should be noted that currently, due to the design of the DevOps tier of CA, Enterprise tier CAs are only supported by the AnyGateway.
-
-# Compatibility
-This AnyGateway is designed to be used with version 21.3.2 of the Keyfactor AnyGateway Framework
-
-# Prerequisites
-## [Authentication](https://cloud.google.com/docs/authentication/production)
-A JSON file generated for a Google Service Account will need to be created and placed on the AnyGateway Server.
-The path of this file into the GOOGLE_APPLICATION_CREDENTIALS environment variable to be used during a CA session.
-Since the AnyGateway is required to run as the Network Service account, the registry will need to be modified to provide the service access to the Environment variable above.
-The GOOGLE_APPLICATION_CREDENTIALS variable should be placed in the following registry location and read access provided:
-
-* HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment
-
-## [Authorization](https://cloud.google.com/certificate-authority-service/docs/reference/permissions-and-roles)
-Currently the only method supported for authentication is a Service Credential with the following IAM authorizations. Any built in role with the below authorizations will function as well.
-* privateca.caPools.list
-* privateca.caPools.get
-* privateca.certificateTemplates.list
-* privateca.certificateTemplates.get
-* privateca.certificateTemplates.use
-* privateca.certificateAuthorities.list
-* privateca.certificateAuthorities.get
-* privateca.certificates.create
-* privateca.certificates.get
-* privateca.certificates.list
-* privateca.certificates.update
-* privateca.reusableConfigs.get
-* privateca.reusableConfigs.list
-* resourcemanager.projects.get
-
-## Certificate Chain
-In order to enroll for certificates the Keyfactor Command server must trust the Private CA chain. Once you create your Root and/or Subordinate CA, make sure to import the certificate chain into the Command Server certificate store
-
-# Install
-* Install the AnyCA Gateway Framework using the MSI from the Software Download Portal
-
-* Download latest successful build from [GitHub](https://github.com/Keyfactor/google-cloud-cagateway)
-
-* Copy *.dll to the Program Files\Keyfactor\ Keyfactor AnyGateway directory
-
-* Update the CAProxyServer.config file
- * Update the CAConnection section to point at the GoogleCAProxy class
- ```xml
-
- ```
- * Depending on the version of the AnyCA Gateway installed, additional binding redirects may need to be applied from the app.config. These redirections will be added to the CAProxyServer.config file
-
-# Configuration
-The following sections will breakdown the required configurations for the AnyGatewayConfig.json file that will be imported to configure the Google CA.
-
-## Templates
-The Google CA has introduced the concept of Templates for the V1 release.
-The product ID mapped below must be the Template Name from the cloud console.
-The API does not provide certificate lifetime information, but any value can be placed here.
-If the value is over the configured value, the Google CA will set to the maximum value as determined by the template configuration.
- ```json
- "Templates": {
- "GoogleCAWebServer": {
- "ProductID": "", /*Value not used, so set to empty string. 'ProductID' element must be present.*/
- "Parameters": {
- "Lifetime": "300",/*days*/
- }
- }
-}
- ```
-## Security
-The security section does not change specifically for the Google CA. Refer to the Keyfactor AnyGateway Documentation for more detail
-```json
- /*Grant permissions on the CA to users or groups in the local domain.
- READ: Enumerate and read contents of certificates.
- ENROLL: Request certificates from the CA.
- OFFICER: Perform certificate functions such as issuance and revocation. This is equivalent to "Issue and Manage" permission on the Microsoft CA.
- ADMINISTRATOR: Configure/reconfigure the gateway.
- Valid permission settings are "Allow", "None", and "Deny".*/
- "Security": {
- "Keyfactor\\Administrator": {
- "READ": "Allow",
- "ENROLL": "Allow",
- "OFFICER": "Allow",
- "ADMINISTRATOR": "Allow"
- },
- "Keyfactor\\gateway_test": {
- "READ": "Allow",
- "ENROLL": "Allow",
- "OFFICER": "Allow",
- "ADMINISTRATOR": "Allow"
- },
- "Keyfactor\\SVC_TimerService": {
- "READ": "Allow",
- "ENROLL": "Allow",
- "OFFICER": "Allow",
- "ADMINISTRATOR": "None"
- },
- "Keyfactor\\SVC_AppPool": {
- "READ": "Allow",
- "ENROLL": "Allow",
- "OFFICER": "Allow",
- "ADMINISTRATOR": "Allow"
- }
- }
-```
-## CerificateManagers
-The Certificate Managers section is optional.
- If configured, all users or groups granted OFFICER permissions under the Security section
- must be configured for at least one Template and one Requester.
- Uses "" to specify all templates. Uses "Everyone" to specify all requesters.
- Valid permission values are "Allow" and "Deny".
-```json
- "CertificateManagers":{
- "DOMAIN\\Username":{
- "Templates":{
- "MyTemplateShortName":{
- "Requesters":{
- "Everyone":"Allow",
- "DOMAIN\\Groupname":"Deny"
- }
- },
- "":{
- "Requesters":{
- "Everyone":"Allow"
- }
- }
- }
- }
- }
-```
-## CAConnection
-The CA Connection section will determine which CA in the Google cloud is integrated with Keyfactor. There are 3 required configuration fields
-* ProjectId
-This is the Resource ID of the project that contains the Google CA Service
-* LocationId
-This is the resource ID of the geographical location (i.e. us-east1) within the Google Cloud
-* CAId
-This is the resource Id of any one of the CAs created in the CA pool using the [Google Cloud Console](https://console.cloud.google.com)
-* CAPoolId
-This is the resource id of the CA Pool created using the [Google Cloud Console](https://console.cloud.google.com)
-
-```json
-"CAConnection": {
- "ProjectId": "concise-frame-296019",
- "LocationId": "us-east1",
- "CAId":"ca-enterprise-subordinate-sandbox-tls",
- "CAPoolId":"gcp-test-pool"
-}
-```
-## GatewayRegistration
-There are no Google Specific Changes for the GatewayRegistration section. Refer to the Keyfactor AnyGateway Documentation for more detail on required changed to support the AnyCA Gateway
-```json
- "GatewayRegistration": {
- "LogicalName": "GoogleCASandbox",
- "GatewayCertificate": {
- "StoreName": "CA",
- "StoreLocation": "LocalMachine",
- "Thumbprint": "bc6d6b168ce5c08a690c15e03be596bbaa095ebf"
- }
- }
-```
-
-## ServiceSettings
-There are no Google Specific Changes for the GatewayRegistration section. Refer to the Keyfactor AnyGateway Documentation for more detail on required changed to support the AnyCA Gateway
-```json
- "ServiceSettings": {
- "ViewIdleMinutes": 8,
- "FullScanPeriodHours": 1,
- "PartialScanPeriodMinutes": 60
- }
-```
diff --git a/src/GoogleCAProxy/App.config b/src/GoogleCAProxy/App.config
new file mode 100644
index 0000000..5da3322
--- /dev/null
+++ b/src/GoogleCAProxy/App.config
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/GoogleCAProxy/GcpLogger.cs b/src/GoogleCAProxy/GcpLogger.cs
deleted file mode 100644
index b509f17..0000000
--- a/src/GoogleCAProxy/GcpLogger.cs
+++ /dev/null
@@ -1,73 +0,0 @@
-using CSS.Common.Logging;
-using Grpc.Core.Logging;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace Keyfactor.AnyGateway.Google
-{
- class GcpLogger : LoggingClientBase, ILogger
-
- {
- public GcpLogger()
- {
- Logger.Info("Create Gcp Logger Instance");
- }
- public void Debug(string message)
- {
- Logger.Debug(message);
- }
-
- public void Debug(string format, params object[] formatArgs)
- {
- Logger.DebugFormat(format,formatArgs);
- }
-
- public void Error(string message)
- {
- Logger.Error(message);
- }
-
- public void Error(string format, params object[] formatArgs)
- {
- Logger.ErrorFormat(format, formatArgs);
- }
-
- public void Error(Exception exception, string message)
- {
- Logger.Error($"{message} | {exception}");
- }
-
- public ILogger ForType()
- {
- return new GcpLogger();
- }
-
- public void Info(string message)
- {
- Logger.Info(message);
- }
-
- public void Info(string format, params object[] formatArgs)
- {
- Logger.InfoFormat(format, formatArgs);
- }
-
- public void Warning(string message)
- {
- Logger.Warn(message);
- }
-
- public void Warning(string format, params object[] formatArgs)
- {
- Logger.WarnFormat(format, formatArgs);
- }
-
- public void Warning(Exception exception, string message)
- {
- Logger.Warn($"{message} | {exception}");
- }
- }
-}
diff --git a/src/GoogleCAProxy/GoogleCAProxy.cs b/src/GoogleCAProxy/GoogleCAProxy.cs
index da9aea3..09f9ab4 100644
--- a/src/GoogleCAProxy/GoogleCAProxy.cs
+++ b/src/GoogleCAProxy/GoogleCAProxy.cs
@@ -1,54 +1,62 @@
-using CAProxy.AnyGateway;
-using CAProxy.AnyGateway.Interfaces;
-using CAProxy.AnyGateway.Models;
-using CAProxy.Common;
-using CSS.PKI;
-using System;
+using System;
+using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
+using System.Security;
using System.Threading;
-//TODO Update for V1
+using CAProxy.AnyGateway;
+using CAProxy.AnyGateway.Interfaces;
+using CAProxy.AnyGateway.Models;
+using CAProxy.Common;
+using CSS.PKI;
+using Google.Api.Gax;
+using Google.Api.Gax.Grpc;
using Google.Cloud.Security.PrivateCA.V1;
using Google.Protobuf.WellKnownTypes;
using Grpc.Core;
-using Google.Api.Gax;
-using CSS.Common.Logging;
-
+using Keyfactor.Logging;
+using Microsoft.Extensions.Logging;
namespace Keyfactor.AnyGateway.Google
{
public class GoogleCAProxy : BaseCAConnector
{
- const string AUTH_ENV_VARIABLE_NAME = "GOOGLE_APPLICATION_CREDENTIALS";
- const string PROJECT_ID_KEY = "ProjectId";
- const string LOCATION_ID_KEY = "LocationId";
- const string CA_ID_KEY = "CAId";
- const string CA_POOL_ID_KEY = "CAPoolId";
- const string LIFETIME_KEY = "Lifetime";
+ private const string AuthEnvVariableName = "GOOGLE_APPLICATION_CREDENTIALS";
+ private const string ProjectIdKey = "ProjectId";
+ private const string LocationIdKey = "LocationId";
+ private const string CaIdKey = "CAId";
+ private const string CaPoolIdKey = "CAPoolId";
+ private const string LifetimeKey = "Lifetime";
+ private const string NoTemplateProductId = "Default";
+
+ private static readonly ILogger Log = LogHandler.GetClassLogger();
private CertificateAuthorityServiceClient GcpClient { get; set; }
private ICAConnectorConfigProvider Config { get; set; }
///
- /// Project Location ID from the Google Cloud Console for the Private CA Project
+ /// Project Location ID from the Google Cloud Console for the Private CA Project
///
private string ProjectId { get; set; }
+
///
- /// Location ID (i.e. us-east1) from the Google Cloud Console for the Private CA deployment
+ /// Location ID (i.e. us-east1) from the Google Cloud Console for the Private CA deployment
///
private string LocationId { get; set; }
+
///
- /// CA Resource ID from the Google Cloud Console for the Private CA to be monitored. To be marked obsolete at GA
+ /// CA Resource ID from the Google Cloud Console for the Private CA to be monitored. To be marked obsolete at GA
///
- private string CAId { get; set; }
+ private string CaId { get; set; }
+
///
- /// CA Pool Resource ID from the Google Cloud Console. This will only be used in the V1 release
+ /// CA Pool Resource ID from the Google Cloud Console. This will only be used in the V1 release
///
- private string CAPoolId { get; set; }
+ private string CaPoolId { get; set; }
///
- /// AnyGateway method to enroll for a certificate from Google CA
+ /// AnyGateway method to enroll for a certificate from Google CA
///
/// Database access to existing CA Certificates
/// base64 encoded string of the Certificate Request
@@ -58,91 +66,173 @@ public class GoogleCAProxy : BaseCAConnector
///
///
///
- public override EnrollmentResult Enroll(ICertificateDataReader certificateDataReader,
- string csr,
- string subject,
- Dictionary san,
- EnrollmentProductInfo productInfo,
- PKIConstants.X509.RequestFormat requestFormat,
- RequestUtilities.EnrollmentType enrollmentType)
+ public override EnrollmentResult Enroll(ICertificateDataReader certificateDataReader,
+ string csr,
+ string subject,
+ Dictionary san,
+ EnrollmentProductInfo productInfo,
+ PKIConstants.X509.RequestFormat requestFormat,
+ RequestUtilities.EnrollmentType enrollmentType)
{
- Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug);
+ Log.MethodEntry();
+
try
{
-
GcpClient = BuildClient();
-
- //var template = GcpClient.GetCertificateTemplate(productInfo.ProductID);
-
- //Logger.Trace($"Template {template.Name} found for enrollment");
-
- var caPoolAsTypedName = CaPoolName.FromProjectLocationCaPool(ProjectId, LocationId, CAPoolId);
-
- Logger.Trace($"Enroll at CA Pool: {caPoolAsTypedName}");
+ }
+ catch
+ {
+ Log.LogError("Failed to create GCP CAS client");
+ throw;
+ }
- if (!int.TryParse(productInfo.ProductParameters[LIFETIME_KEY], out int lifetimeInDays))
+ int lifetimeInDays = 365; // Default value
+ if (productInfo.ProductParameters.TryGetValue(LifetimeKey, out string lifetimeInDaysString))
+ {
+ if (!int.TryParse(lifetimeInDaysString, out lifetimeInDays))
{
- Logger.Warn($"Unable to parse certificate {LIFETIME_KEY} from Product Parameters for Product Id {productInfo.ProductID}. Set Lifetime to 365 days.");
- lifetimeInDays = 365;
+ Log.LogWarning(
+ $"Unable to parse certificate {LifetimeKey} from Product Parameters for Product Id {productInfo.ProductID}. Using default value of 365 days.");
}
- Logger.Trace($"Submit Certificate Request for {subject} with {lifetimeInDays} days validity");
- var certificate = new Certificate()
- {
- PemCsr = $"-----BEGIN NEW CERTIFICATE REQUEST-----\n{pemify(csr)}\n-----END NEW CERTIFICATE REQUEST-----",
- Lifetime = Duration.FromTimeSpan(new TimeSpan(lifetimeInDays, 0, 0, 0, 0))//365 day default or defined by config
- };
+ }
+ else
+ {
+ Log.LogDebug(
+ $"LifetimeKey not found in Product Parameters for Product Id {productInfo.ProductID}. Using default value of 365 days.");
+ }
- DateTime now = DateTime.Now;
- var createCertificateRequest = new CreateCertificateRequest() {
- ParentAsCaPoolName = caPoolAsTypedName,
- Certificate = certificate,
- //RequestId="",//if used, this needs to be durable between reties
- CertificateId = $"{now:yyyy}{now:MM}{now:dd}-{now:HH}{now:mm}{now:ss}"//ID is required for Enterprise tier CAs and ignored for other.
- };
+ CertificateConfig certConfig = new CertificateConfig();
+ certConfig.SubjectConfig = new CertificateConfig.Types.SubjectConfig();
+ bool useConfig = false;
+ if (!string.IsNullOrEmpty(subject))
+ {
+ certConfig.SubjectConfig.Subject = new Subject
+ {
+ CommonName = ParseSubject(subject, "CN=", false),
+ Organization = ParseSubject(subject, "O=", false),
+ OrganizationalUnit = ParseSubject(subject, "OU=", false),
+ CountryCode = ParseSubject(subject, "C=", false),
+ Locality = ParseSubject(subject, "L=", false)
+ };
+ useConfig = true;
+ }
+ var dnsSans = new List();
+ if (san != null & san.Count > 0)
+ {
+ var dnsKeys = san.Keys.Where(k => k.IndexOf("dns", StringComparison.OrdinalIgnoreCase) >= 0);
+ foreach (var key in dnsKeys)
+ {
+ dnsSans.AddRange(san[key]);
+ }
+ }
+ if (dnsSans.Count > 0)
+ {
+ certConfig.SubjectConfig.SubjectAltName = new SubjectAltNames
+ {
+ DnsNames = { dnsSans }
+ };
+ useConfig = true;
+ }
+
+ Log.LogDebug($"Configuring {typeof(Certificate)} for {subject} with {lifetimeInDays} days validity");
+ Certificate certificate = new Certificate
+ {
+ PemCsr =
+ $"-----BEGIN NEW CERTIFICATE REQUEST-----\n{pemify(csr)}\n-----END NEW CERTIFICATE REQUEST-----",
+ Lifetime = Duration.FromTimeSpan(new TimeSpan(lifetimeInDays, 0, 0, 0,
+ 0)), //365 day default or defined by config
+ Config = (useConfig) ? certConfig : null
+ };
- var response = GcpClient.CreateCertificate(createCertificateRequest);
+ if (productInfo.ProductID == NoTemplateProductId)
+ {
+ Log.LogDebug(
+ $"{NoTemplateProductId} template selected - Certificate enrollment will defer to the baseline values and policy configured by the CA Pool.");
+ }
+ else
+ {
+ Log.LogDebug(
+ $"Configuring {typeof(Certificate)} with the {productInfo.ProductID} Certificate Template.");
+ CertificateTemplateName template = new CertificateTemplateName(ProjectId, LocationId, productInfo.ProductID);
+ certificate.CertificateTemplate = template.ToString();
+ }
- return new EnrollmentResult
- {
- Status = 20,
- CARequestID = response.CertificateName?.CertificateId,
- Certificate = response.PemCertificate
- };
+ DateTime now = DateTime.Now;
+ CaPoolName caPoolAsTypedName = CaPoolName.FromProjectLocationCaPool(ProjectId, LocationId, CaPoolId);
+ Log.LogDebug(
+ $"Configuring {typeof(CreateCertificateRequest)} with the configured {typeof(Certificate)} to enroll {subject} with the {caPoolAsTypedName} CA Pool");
+ CreateCertificateRequest createCertificateRequest = new CreateCertificateRequest
+ {
+ ParentAsCaPoolName = caPoolAsTypedName,
+ Certificate = certificate,
+ //RequestId="",//if used, this needs to be durable between reties
+ CertificateId = Guid.NewGuid().ToString() //ID is required for Enterprise tier CAs and ignored for other.
+ };
+
+ if (!string.IsNullOrEmpty(CaId))
+ {
+ Log.LogDebug(
+ $"CAConnection section contained a non-empty CAId - Certificate will be enrolled using the CA with ID {CaId}");
+ createCertificateRequest.IssuingCertificateAuthorityId = CaId;
+ }
+
+ Certificate response;
+ try
+ {
+ Log.LogDebug($"Submitting CreateCertificate RPC for {subject}");
+ response = GcpClient.CreateCertificate(createCertificateRequest);
+ Log.LogDebug($"RPC was successful - minted certificate with resource name {response.Name}");
}
catch (RpcException gEx)
{
+ string message =
+ $"Could not complete certificate enrollment. RPC was unsuccessful. Status Code: {gEx.StatusCode} | Detail: {gEx.Status.Detail}";
+ Log.LogError(message);
return new EnrollmentResult
{
Status = 30,
- StatusMessage = $"Could not complete certificate enrollment. Status Code: {gEx.StatusCode} | Detail: {gEx.Status.Detail}"
+ StatusMessage = message
};
}
catch (Exception ex)
{
- return new EnrollmentResult {
- Status=30,
- StatusMessage = $"Could not complete certificate enrollment. {ex.Message}"
+ string message = $"Exception caught - Could not complete certificate enrollment: {ex}";
+ Log.LogError(message);
+ return new EnrollmentResult
+ {
+ Status = 30,
+ StatusMessage = message
};
}
+
+ return new EnrollmentResult
+ {
+ Status = 20,
+ CARequestID = response.CertificateName?.CertificateId,
+ Certificate = response.PemCertificate
+ };
}
+
///
- /// AnyGateway method to get a single certificate's detail from the CA
+ /// AnyGateway method to get a single certificate's detail from the CA
///
/// CA Id returned during inital synchronization
///
public override CAConnectorCertificate GetSingleRecord(string caRequestID)
{
- Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug);
+ Log.MethodEntry();
try
{
GcpClient = BuildClient();
- var cloudCert = GcpClient.GetCertificate(new CertificateName(ProjectId, LocationId, CAPoolId, caRequestID));
+ Certificate cloudCert =
+ GcpClient.GetCertificate(new CertificateName(ProjectId, LocationId, CaPoolId, caRequestID));
return ProcessCAResponse(cloudCert);
}
catch (RpcException gEx)
{
- throw new Exception($"Could not retrieve certificate. Status Code: {gEx.StatusCode} | Detail: {gEx.Status.Detail}");
+ throw new Exception(
+ $"Could not retrieve certificate. Status Code: {gEx.StatusCode} | Detail: {gEx.Status.Detail}");
}
catch (Exception ex)
{
@@ -151,38 +241,37 @@ public override CAConnectorCertificate GetSingleRecord(string caRequestID)
}
///
- /// AnyGateway method called before most AnyGateway functions
+ /// AnyGateway method called before most AnyGateway functions
///
/// Existing configuration extracted from the AnyGateway database
public override void Initialize(ICAConnectorConfigProvider configProvider)
{
- Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug);
+ Log.MethodEntry();
try
{
Config = configProvider;
- ProjectId = Config.CAConnectionData[PROJECT_ID_KEY] as string;
- LocationId = Config.CAConnectionData[LOCATION_ID_KEY] as string;
- CAPoolId = Config.CAConnectionData[CA_POOL_ID_KEY] as string;
- CAId = Config.CAConnectionData[CA_ID_KEY] as string;
+ ProjectId = Config.CAConnectionData[ProjectIdKey] as string;
+ LocationId = Config.CAConnectionData[LocationIdKey] as string;
+ CaPoolId = Config.CAConnectionData[CaPoolIdKey] as string;
+ CaId = Config.CAConnectionData[CaIdKey] as string;
}
catch (Exception ex)
{
- Logger.Error(ex);
+ Log.LogError($"Failed to initialize GCP CAS CAPlugin: {ex}");
}
}
///
- /// Certutil response to the certutil -ping [-config host\logical] command
+ /// Certutil response to the certutil -ping [-config host\logical] command
///
public override void Ping()
{
- Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug);
- Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug);
-
+ Log.MethodEntry();
+ Log.MethodExit();
}
///
- /// AnyGateway method to revoke a certificate
+ /// AnyGateway method to revoke a certificate
///
///
///
@@ -190,142 +279,148 @@ public override void Ping()
///
public override int Revoke(string caRequestID, string hexSerialNumber, uint revocationReason)
{
- Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug);
+ Log.MethodEntry();
try
{
GcpClient = BuildClient();
- CertificateName certId = new CertificateName(ProjectId, LocationId, CAPoolId, caRequestID);
+ CertificateName certId = new CertificateName(ProjectId, LocationId, CaPoolId, caRequestID);
- RevokeCertificateRequest request = new RevokeCertificateRequest()
- {
+ RevokeCertificateRequest request = new RevokeCertificateRequest
+ {
CertificateName = certId,
Reason = (RevocationReason)revocationReason
};
- Logger.Trace($"Revoking certificate id {certId}");
- var response = GcpClient.RevokeCertificate(request);
+ Log.LogTrace($"Revoking certificate id {certId}");
+ Certificate response = GcpClient.RevokeCertificate(request);
return Convert.ToInt32(PKIConstants.Microsoft.RequestDisposition.REVOKED);
;
}
catch (RpcException gEx)
{
- Logger.Error($"Unable to revoke certificate. Status Code: {gEx.StatusCode} | Status:{gEx.Status}");
+ Log.LogError($"Unable to revoke certificate. Status Code: {gEx.StatusCode} | Status:{gEx.Status}");
throw gEx;
}
catch (Exception ex)
{
- Logger.Error($"Unable to revoke certificate. {ex.Message}");
+ Log.LogError($"Unable to revoke certificate. {ex.Message}");
throw ex;
}
}
///
- /// AnyGateway method to syncronize Google CA Certificates
+ /// AnyGateway method to syncronize Google CA Certificates
///
/// Database access to the current certificates for the CA
///
/// Detail about the CA being synchronized
///
public override void Synchronize(ICertificateDataReader certificateDataReader,
- BlockingCollection blockingBuffer,
- CertificateAuthoritySyncInfo certificateAuthoritySyncInfo,
- CancellationToken cancelToken)
+ BlockingCollection blockingBuffer,
+ CertificateAuthoritySyncInfo certificateAuthoritySyncInfo,
+ CancellationToken cancelToken)
{
- Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug);
+ Log.MethodEntry();
try
{
GcpClient = BuildClient();
//For sync we still need to specify the CA ID since the pool will not provide a list of certs.
//Do we have a CA in Keyfactor for each even thought issuance and revocation will be pool level? Probably
- CertificateAuthorityName caName = CertificateAuthorityName.FromProjectLocationCaPoolCertificateAuthority(ProjectId, LocationId, CAPoolId, CAId);
+ CertificateAuthorityName caName =
+ CertificateAuthorityName.FromProjectLocationCaPoolCertificateAuthority(ProjectId, LocationId,
+ CaPoolId, CaId);
if (certificateAuthoritySyncInfo.DoFullSync)
{
- var ca = GcpClient.GetCertificateAuthority(caName);
- ProcessCACertificateList(ca, blockingBuffer, cancelToken);
+ CertificateAuthority ca = GcpClient.GetCertificateAuthority(caName);
+ ProcessCACertificateList(ca, blockingBuffer, cancelToken);
}
- ListCertificatesRequest syncRequest = new ListCertificatesRequest()
+ ListCertificatesRequest syncRequest = new ListCertificatesRequest
{
- ParentAsCaPoolName = CaPoolName.FromProjectLocationCaPool(ProjectId,LocationId,CAPoolId),
+ ParentAsCaPoolName = CaPoolName.FromProjectLocationCaPool(ProjectId, LocationId, CaPoolId)
};
if (!certificateAuthoritySyncInfo.DoFullSync)
{
- Timestamp lastSyncTime = certificateAuthoritySyncInfo.LastFullSync.Value.ToUniversalTime().ToTimestamp();
- Logger.Trace($"Executing an incremental sync. Filter list by update_time >= {lastSyncTime.ToDateTime().ToLocalTime()}");
+ Timestamp lastSyncTime =
+ certificateAuthoritySyncInfo.LastFullSync.Value.ToUniversalTime().ToTimestamp();
+ Log.LogTrace(
+ $"Executing an incremental sync. Filter list by update_time >= {lastSyncTime.ToDateTime().ToLocalTime()}");
syncRequest.Filter = $"update_time >= {lastSyncTime}";
}
- var responseList = GcpClient.ListCertificates(syncRequest);
+ PagedEnumerable responseList =
+ GcpClient.ListCertificates(syncRequest);
ProcessCertificateList(responseList, blockingBuffer, cancelToken);
}
catch (RpcException gEx)
{
- Logger.Error($"Unable to get CA Certificate List. {gEx.StatusCode} | {gEx.Status}");
+ Log.LogError($"Unable to get CA Certificate List. {gEx.StatusCode} | {gEx.Status}");
}
catch (Exception ex)
{
- Logger.Error($"Unhandled Exception: {ex}");
+ Log.LogError($"Unhandled Exception: {ex}");
}
}
///
- /// AnyGateway method to validate connection detail (CAConnection section) during the Set-KeyfactorGatewayConfig cmdlet
+ /// AnyGateway method to validate connection detail (CAConnection section) during the Set-KeyfactorGatewayConfig cmdlet
///
/// CAConnection section of the AnyGateway JSON file
public override void ValidateCAConnectionInfo(Dictionary connectionInfo)
{
- Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug);
- //connectionInfo is the currently imported values
- //CONFIG is the existing configuration from the initalize
+ Log.MethodEntry();
List errors = new List();
- Logger.Trace("Checking required CAConnection config");
- errors.AddRange(CheckRequiredValues(connectionInfo, PROJECT_ID_KEY, LOCATION_ID_KEY, CA_POOL_ID_KEY, CA_ID_KEY));
+ Log.LogTrace("Checking required CAConnection config");
+ errors.AddRange(CheckRequiredValues(connectionInfo, ProjectIdKey, LocationIdKey, CaPoolIdKey));
- Logger.Trace("Checking permissions for JSON license file");
+ Log.LogTrace("Checking permissions for JSON license file");
errors.AddRange(CheckEnvrionmentVariables());
- Logger.Trace("Checking connectivity and CA type");
+ Log.LogTrace("Checking connectivity and CA type");
errors.AddRange(CheckCAConfig(connectionInfo));
- if (errors.Any())
- {
- throw new Exception(String.Join("|", errors.ToArray()));
- }
+ if (errors.Any()) throw new Exception(string.Join("|", errors.ToArray()));
}
///
- /// AnyGateway method to validate product info (Template section) during the Set-KeyfactorGatewayConfig cmdlet
+ /// AnyGateway method to validate product info (Template section) during the Set-KeyfactorGatewayConfig cmdlet
///
/// Parameters section of the AnyGateway JSON file
/// CAConnection section of the AnyGateway JSON file
- public override void ValidateProductInfo(EnrollmentProductInfo productInfo, Dictionary connectionInfo)
+ public override void ValidateProductInfo(EnrollmentProductInfo productInfo,
+ Dictionary connectionInfo)
{
- Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug);
+ Log.MethodEntry();
//TODO: Evaluate Template (if avaiable) based on ProductInfo
//https://cloud.google.com/certificate-authority-service/docs/reference/rest/v1/projects.locations.certificateTemplates#CertificateTemplate
- Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug);
+ Log.MethodExit();
}
#region Private Helper Methods
+
///
- /// Method to process Issued certificates from the Goocle CA
+ /// Method to process Issued certificates from the Goocle CA
///
- /// from a full or incremental sync request to the Google CA
+ ///
+ /// from a full or incremental sync request to the
+ /// Google CA
+ ///
///
///
- private void ProcessCertificateList(PagedEnumerable responseList, BlockingCollection blockingBuffer, CancellationToken cancelToken)
+ private void ProcessCertificateList(PagedEnumerable responseList,
+ BlockingCollection blockingBuffer, CancellationToken cancelToken)
{
- Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug);
+ Log.MethodEntry();
int totalCertsProcessed = 0;
int pagesProcessed = 0;
- foreach (var page in responseList.AsRawResponses())
+ foreach (ListCertificatesResponse page in responseList.AsRawResponses())
{
if (page.Count() == 0)
{
- Logger.Warn($"Incremental Sync Returned No Results");
+ Log.LogWarning("Incremental Sync Returned No Results");
continue;
}
@@ -334,7 +429,7 @@ private void ProcessCertificateList(PagedEnumerable 0)
- {
- Logger.Warn($"Adding of {caCert.CARequestID} to queue was blocked. Took a total of {blockedCount} tries to process.");
- }
+ Log.LogWarning(
+ $"Adding of {caCert.CARequestID} to queue was blocked. Took a total of {blockedCount} tries to process.");
pageCertsProcessed++;
totalCertsProcessed++;
}
@@ -352,26 +446,30 @@ private void ProcessCertificateList(PagedEnumerable
- /// Method to process the Issuing Certificate of a Google CA
+ /// Method to process the Issuing Certificate of a Google CA
///
- /// to process certificate from
+ /// to process certificate from
/// BlockingCollection provided by the Command platform for syncing CA certificates
///
- private void ProcessCACertificateList(CertificateAuthority ca, BlockingCollection blockingBuffer, CancellationToken cancelToken)
+ private void ProcessCACertificateList(CertificateAuthority ca,
+ BlockingCollection blockingBuffer, CancellationToken cancelToken)
{
- Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug);
+ Log.MethodEntry();
int caCertsProcessed = 0;
do
{
- var caPemCert = ca.PemCaCertificates.ElementAt(caCertsProcessed);
+ string caPemCert = ca.PemCaCertificates.ElementAt(caCertsProcessed);
CAConnectorCertificate caCert = new CAConnectorCertificate
{
@@ -386,57 +484,112 @@ private void ProcessCACertificateList(CertificateAuthority ca, BlockingCollectio
if (blockingBuffer.TryAdd(caCert, 50, cancelToken))
{
if (blockedCount > 0)
- {
- Logger.Warn($"Adding of {caCert.CARequestID} to queue was blocked. Took a total of {blockedCount} tries to process.");
- }
+ Log.LogWarning(
+ $"Adding of {caCert.CARequestID} to queue was blocked. Took a total of {blockedCount} tries to process.");
caCertsProcessed++;
}
else
{
blockedCount++;
}
- } while (caCertsProcessed < (ca.PemCaCertificates.Count - 1) );
+ } while (caCertsProcessed < ca.PemCaCertificates.Count - 1);
}
- ///
- /// Validate CA Configuration by attempting to connect and validate
- ///
- /// CAConnection Details object from the AnyGateway Config JSON file
- ///
- private static IEnumerable CheckCAConfig(Dictionary connectionInfo)
+ private static IEnumerable ValidateCaPool(Dictionary connectionInfo)
{
List returnValue = new List();
try
{
- var ca = BuildClient().GetCertificateAuthority(new GetCertificateAuthorityRequest
+ Log.LogDebug($"Validating that service account can access CA Pool with ID {connectionInfo[CaPoolIdKey] as string}");
+ CaPool caPool = BuildClient().GetCaPool(new GetCaPoolRequest()
{
- CertificateAuthorityName = CertificateAuthorityName.FromProjectLocationCaPoolCertificateAuthority(
- connectionInfo[PROJECT_ID_KEY] as string,
- connectionInfo[LOCATION_ID_KEY] as string,
- connectionInfo[CA_POOL_ID_KEY] as string,
- connectionInfo[CA_ID_KEY] as string
+ CaPoolName = CaPoolName.FromProjectLocationCaPool(
+ connectionInfo[ProjectIdKey] as string,
+ connectionInfo[LocationIdKey] as string,
+ connectionInfo[CaPoolIdKey] as string
)
});
- if (ca.Tier == CaPool.Types.Tier.Devops)
- {
- returnValue.Add($"{ca.Tier} is an unsupported CA configuration");
- }
+ if (caPool.Tier == CaPool.Types.Tier.Devops)
+ {
+ string message = $"{caPool.Tier} is an unsupported CA configuration";
+ Log.LogError(message);
+ returnValue.Add(message);
+ }
}
catch (RpcException gEx)
{
- returnValue.Add($"Unable to connect to CA. Status Code: {gEx.StatusCode} | Status: {gEx.Status}");
+ string message = $"Unable to connect to CA Pool. Status Code: {gEx.StatusCode} | Status: {gEx.Status}";
+ Log.LogError(message);
+ returnValue.Add(message);
}
catch (Exception ex)
{
- returnValue.Add($"Unable to connect to CA. Detail: {ex.Message}");
+ string message = $"Unable to connect to CA. Detail: {ex.Message}";
+ Log.LogError(message);
+ returnValue.Add(message);
}
return returnValue;
}
+ private static IEnumerable ValidateCa(Dictionary connectionInfo)
+ {
+ List returnValue = new List();
+ try
+ {
+ Log.LogDebug($"Validating that service account can access CA with ID {connectionInfo[CaIdKey] as string}");
+ CertificateAuthority ca = BuildClient().GetCertificateAuthority(new GetCertificateAuthorityRequest
+ {
+ CertificateAuthorityName = CertificateAuthorityName.FromProjectLocationCaPoolCertificateAuthority(
+ connectionInfo[ProjectIdKey] as string,
+ connectionInfo[LocationIdKey] as string,
+ connectionInfo[CaPoolIdKey] as string,
+ connectionInfo[CaIdKey] as string
+ )
+ });
+
+ if (ca.Tier == CaPool.Types.Tier.Devops)
+ {
+ string message = $"{ca.Tier} is an unsupported CA configuration";
+ Log.LogError(message);
+ returnValue.Add(message);
+ }
+ }
+ catch (RpcException gEx)
+ {
+ string message = $"Unable to connect to CA. Status Code: {gEx.StatusCode} | Status: {gEx.Status}";
+ Log.LogError(message);
+ returnValue.Add(message);
+ }
+ catch (Exception ex)
+ {
+ string message = $"Unable to connect to CA. Detail: {ex.Message}";
+ Log.LogError(message);
+ returnValue.Add(message);
+ }
+
+ return returnValue;
+ }
///
- /// Determines if the provided keys have been configured
+ /// Validate CA Configuration by attempting to connect and validate
+ ///
+ /// CAConnection Details object from the AnyGateway Config JSON file
+ ///
+ private static IEnumerable CheckCAConfig(Dictionary connectionInfo)
+ {
+ if (connectionInfo.TryGetValue(CaIdKey, out object id) && !string.IsNullOrEmpty(id as string))
+ {
+ Log.LogDebug($"GCP CAS CAProxy configured with a non-empty {CaIdKey} - validating that {id as string} exists.");
+ return ValidateCa(connectionInfo);
+ }
+
+ Log.LogDebug($"GCP CAS CAProxy configured with an empty or non-existant {CaIdKey} - validating that CA pool exists.");
+ return ValidateCaPool(connectionInfo);
+ }
+
+ ///
+ /// Determines if the provided keys have been configured
///
/// CAConnection Details object from the AnyGateway Config JSON file
/// List of keys to validate
@@ -445,96 +598,142 @@ private static List CheckRequiredValues(Dictionary conne
{
List errors = new List();
foreach (string s in args)
- {
- if (String.IsNullOrEmpty(connectionInfo[s] as string))
+ if (string.IsNullOrEmpty(connectionInfo[s] as string))
errors.Add($"{s} is a required value");
- }
return errors;
}
///
- /// Determines if the AnyGateway service can read from the GOOGLE_APPLICATION_CREDENTIALS machine envrionment variable and read the contents of the
- /// file.
+ /// Determines if the AnyGateway service can read from the GOOGLE_APPLICATION_CREDENTIALS machine envrionment variable
+ /// and read the contents of the
+ /// file.
///
- /// the contains any error messages for items failing validation
+ /// the contains any error messages for items failing validation
private static List CheckEnvrionmentVariables()
{
List errors = new List();
try
{
- string envrionmentVariablePath = Environment.GetEnvironmentVariable(AUTH_ENV_VARIABLE_NAME, EnvironmentVariableTarget.Machine);
- if (String.IsNullOrEmpty(envrionmentVariablePath))
- errors.Add($"{AUTH_ENV_VARIABLE_NAME} must be conifgured with a JSON credential file");
+ string envrionmentVariablePath =
+ Environment.GetEnvironmentVariable(AuthEnvVariableName, EnvironmentVariableTarget.Machine);
+ if (string.IsNullOrEmpty(envrionmentVariablePath))
+ {
+ string message = $"{AuthEnvVariableName} must be conifgured with a JSON credential file";
+ Log.LogError(message);
+ errors.Add(message);
+ }
if (!envrionmentVariablePath.IsFullPathReadable())
- errors.Add($"Cannot read license file at {envrionmentVariablePath}");
+ {
+ string message = $"Cannot read license file at {envrionmentVariablePath}";
+ Log.LogError(message);
+ errors.Add(message);
+ }
}
- catch (System.Security.SecurityException)
+ catch (SecurityException)
{
- errors.Add($"Access denied to {AUTH_ENV_VARIABLE_NAME} at \"HKLM\\System\\CurrentControlSet\\Control\\Session Manager\\Environment\" registry key");
+ string message =
+ $"Access denied to {AuthEnvVariableName} at \"HKLM\\System\\CurrentControlSet\\Control\\Session Manager\\Environment\" registry key";
+ Log.LogError(message);
+ errors.Add(message);
}
return errors;
}
+
///
- /// Creates a Keyfactor AnyGateway Certificate Type from the GCP Certificate Type
+ /// Creates a Keyfactor AnyGateway Certificate Type from the GCP Certificate Type
///
///
- /// parsed from a object
+ /// parsed from a object
private CAConnectorCertificate ProcessCAResponse(Certificate caCertificate)
{
- Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug);
- return new CAConnectorCertificate()
+ Log.MethodEntry();
+ return new CAConnectorCertificate
{
- CARequestID = caCertificate.CertificateName.CertificateId,//limited to 100 characters. use cert id only Required
+ CARequestID =
+ caCertificate.CertificateName.CertificateId, //limited to 100 characters. use cert id only Required
CSR = caCertificate.PemCsr,
Certificate = caCertificate.PemCertificate,
- Status = caCertificate.RevocationDetails is null ? 20 : 21,//required
- SubmissionDate = caCertificate.CreateTime?.ToDateTime(),//Required
+ Status = caCertificate.RevocationDetails is null ? 20 : 21, //required
+ SubmissionDate = caCertificate.CreateTime?.ToDateTime(), //Required
ResolutionDate = caCertificate.CreateTime?.ToDateTime(),
RevocationDate = caCertificate.RevocationDetails?.RevocationTime.ToDateTime(),
- RevocationReason = caCertificate.RevocationDetails is null ? -1 : (int)caCertificate.RevocationDetails.RevocationState //assumes revocation reasons match Keyfactor
+ RevocationReason = caCertificate.RevocationDetails is null
+ ? -1
+ : (int)caCertificate.RevocationDetails.RevocationState //assumes revocation reasons match Keyfactor
};
-
}
///
- /// Add new line every 64 characters to propertly format a base64 string as PEM
+ /// Add new line every 64 characters to propertly format a base64 string as PEM
///
- private static Func pemify = (ss => ss.Length <= 64 ? ss : ss.Substring(0, 64) + "\n" + pemify(ss.Substring(64)));
-
+ private static readonly Func pemify = ss =>
+ ss.Length <= 64 ? ss : ss.Substring(0, 64) + "\n" + pemify(ss.Substring(64));
+
///
- /// Build a new instance of the CertificateAuthorityServiceClient with explict credentials from the Server Envrionment Variable
+ /// Build a new instance of the CertificateAuthorityServiceClient with explict credentials from the Server Envrionment
+ /// Variable
///
///
private static CertificateAuthorityServiceClient BuildClient()
{
- var caClient = new CertificateAuthorityServiceClientBuilder
+ string credentialsPath = Environment.GetEnvironmentVariable(AuthEnvVariableName, EnvironmentVariableTarget.Machine);
+
+ // Set the gRPC buffer size to -1 for "no limit"
+ // https://grpc.github.io/grpc/core/group__grpc__arg__keys.html#ga813f94f9ac3174571dd712c96cdbbdc1
+ GrpcChannelOptions grpcChannelOptions = GrpcChannelOptions.Empty.WithMaxReceiveMessageSize(-1);
+
+ CertificateAuthorityServiceClientBuilder caClientBuilder = new CertificateAuthorityServiceClientBuilder
{
- CredentialsPath = Environment.GetEnvironmentVariable(AUTH_ENV_VARIABLE_NAME, EnvironmentVariableTarget.Machine)
+ CredentialsPath = credentialsPath,
+ GrpcChannelOptions = grpcChannelOptions,
};
- return caClient.Build();
- }
+ return caClientBuilder.Build();
+ }
- #endregion
-
- #region Obsolete Methods
- [Obsolete]
- public override EnrollmentResult Enroll(string csr, string subject, Dictionary san, EnrollmentProductInfo productInfo, CSS.PKI.PKIConstants.X509.RequestFormat requestFormat, RequestUtilities.EnrollmentType enrollmentType)
+ private static string ParseSubject(string subject, string rdn, bool required = true)
+ {
+ string escapedSubject = subject.Replace("\\,", "|");
+ string rdnString = escapedSubject.Split(',').ToList().Where(x => x.Contains(rdn)).FirstOrDefault();
+
+ if (!string.IsNullOrEmpty(rdnString))
+ {
+ return rdnString.Replace(rdn, "").Replace("|", ",").Trim();
+ }
+ else if (required)
+ {
+ throw new Exception($"The request is missing a {rdn} value");
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ #endregion
+
+ #region Obsolete Methods
+
+ [Obsolete]
+ public override EnrollmentResult Enroll(string csr, string subject, Dictionary san,
+ EnrollmentProductInfo productInfo, PKIConstants.X509.RequestFormat requestFormat,
+ RequestUtilities.EnrollmentType enrollmentType)
{
throw new NotImplementedException();
}
[Obsolete]
public override void Synchronize(ICertificateDataReader certificateDataReader,
- BlockingCollection blockingBuffer,
- CertificateAuthoritySyncInfo certificateAuthoritySyncInfo,
- CancellationToken cancelToken,
- string logicalName)
+ BlockingCollection blockingBuffer,
+ CertificateAuthoritySyncInfo certificateAuthoritySyncInfo,
+ CancellationToken cancelToken,
+ string logicalName)
{
throw new NotImplementedException();
}
+
#endregion
}
-}
+}
\ No newline at end of file
diff --git a/src/GoogleCAProxy/GoogleCAProxy.csproj b/src/GoogleCAProxy/GoogleCAProxy.csproj
index a1b2c11..f0e6a0d 100644
--- a/src/GoogleCAProxy/GoogleCAProxy.csproj
+++ b/src/GoogleCAProxy/GoogleCAProxy.csproj
@@ -1,6 +1,5 @@
-
Debug
@@ -10,20 +9,21 @@
Properties
Keyfactor.AnyGateway.Google
GoogleCAProxy
- v4.6.2
+ v4.7.2
512
true
-
-
+ OnBuildSuccess
+ true
true
full
false
- bin\Debug\
+ bin\Debug
DEBUG;TRACE
prompt
4
+ False
pdbonly
@@ -32,113 +32,21 @@
TRACE
prompt
4
-
-
- true
-
-
- bin\Prerelease\
+ False
-
- packages\BouncyCastle.1.8.5\lib\BouncyCastle.Crypto.dll
-
-
- packages\Keyfactor.AnyGateway.SDK.21.3.2\lib\net462\CAProxy.AnyGateway.Core.dll
-
-
- packages\Keyfactor.AnyGateway.SDK.21.3.2\lib\net462\CAProxy.Interfaces.dll
-
-
- packages\Keyfactor.AnyGateway.SDK.21.3.2\lib\net462\CAProxyDAL.dll
-
-
- packages\Common.Logging.3.4.1\lib\net40\Common.Logging.dll
-
-
- packages\Common.Logging.Core.3.4.1\lib\net40\Common.Logging.Core.dll
-
-
- packages\Keyfactor.AnyGateway.SDK.21.3.2\lib\net462\CommonCAProxy.dll
-
-
- packages\CSS.Common.1.7.0\lib\net462\CSS.Common.dll
-
-
- packages\CSS.PKI.2.13.0\lib\net462\CSS.PKI.dll
-
-
- packages\Google.Api.CommonProtos.2.3.0\lib\net461\Google.Api.CommonProtos.dll
-
-
- packages\Google.Api.Gax.3.4.0\lib\net461\Google.Api.Gax.dll
-
-
- packages\Google.Api.Gax.Grpc.3.4.0\lib\net461\Google.Api.Gax.Grpc.dll
-
-
- packages\Google.Api.Gax.Grpc.GrpcCore.3.4.0\lib\net461\Google.Api.Gax.Grpc.GrpcCore.dll
-
-
- packages\Google.Apis.1.52.0\lib\net45\Google.Apis.dll
-
-
- packages\Google.Apis.Auth.1.52.0\lib\net461\Google.Apis.Auth.dll
+
+ $(NuGetPackageRoot)keyfactor.anygateway.sdk\24.2.0-prerelease-47446\lib\net472\CAProxy.AnyGateway.Core.dll
-
- packages\Google.Apis.Auth.1.52.0\lib\net461\Google.Apis.Auth.PlatformServices.dll
+
+ $(NuGetPackageRoot)keyfactor.anygateway.sdk\24.2.0-prerelease-47446\lib\net472\CAProxy.Interfaces.dll
-
- packages\Google.Apis.Core.1.52.0\lib\net45\Google.Apis.Core.dll
-
-
- packages\Google.Apis.1.52.0\lib\net45\Google.Apis.PlatformServices.dll
-
-
- packages\Google.Cloud.Security.PrivateCA.V1.1.0.0\lib\net461\Google.Cloud.Security.PrivateCA.V1.dll
-
-
- packages\Google.Cloud.Security.PrivateCA.V1Beta1.1.0.0-beta01\lib\net461\Google.Cloud.Security.PrivateCA.V1Beta1.dll
-
-
- packages\Google.LongRunning.2.2.0\lib\net461\Google.LongRunning.dll
-
-
- packages\Google.Protobuf.3.15.8\lib\net45\Google.Protobuf.dll
-
-
- packages\Grpc.Auth.2.38.0\lib\net45\Grpc.Auth.dll
-
-
- packages\Grpc.Core.2.38.0\lib\net45\Grpc.Core.dll
-
-
- packages\Grpc.Core.Api.2.38.0\lib\net45\Grpc.Core.Api.dll
-
-
- packages\Microsoft.Bcl.AsyncInterfaces.5.0.0\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll
-
-
- packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll
+
+ $(NuGetPackageRoot)keyfactor.anygateway.sdk\24.2.0-prerelease-47446\lib\net472\CommonCAProxy.dll
-
- packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll
-
-
- packages\System.Memory.4.5.4\lib\net461\System.Memory.dll
-
-
- packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll
-
-
- packages\System.Runtime.CompilerServices.Unsafe.6.0.0-preview.4.21253.7\lib\net45\System.Runtime.CompilerServices.Unsafe.dll
-
-
- packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll
-
@@ -147,29 +55,39 @@
-
-
+
-
- Always
-
-
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
- This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/GoogleCAProxy/GoogleCAProxy.sln b/src/GoogleCAProxy/GoogleCAProxy.sln
index fd2ea43..e778ab5 100644
--- a/src/GoogleCAProxy/GoogleCAProxy.sln
+++ b/src/GoogleCAProxy/GoogleCAProxy.sln
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 16
-VisualStudioVersion = 16.0.30611.23
+# Visual Studio Version 17
+VisualStudioVersion = 17.10.35027.167
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GoogleCAProxy", "GoogleCAProxy.csproj", "{011DC646-BEF9-4D3B-9D20-CA444A26B355}"
EndProject
@@ -14,7 +14,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
..\..\README.md = ..\..\README.md
EndProjectSection
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GoogleCASandbox", "..\GoogleCASandbox\GoogleCASandbox.csproj", "{863DC1E0-8E93-4EE6-8404-75C34838FF2A}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GoogleCASandbox", "..\GoogleCASandbox\GoogleCASandbox.csproj", "{863DC1E0-8E93-4EE6-8404-75C34838FF2A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -25,8 +25,8 @@ Global
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{011DC646-BEF9-4D3B-9D20-CA444A26B355}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{011DC646-BEF9-4D3B-9D20-CA444A26B355}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {011DC646-BEF9-4D3B-9D20-CA444A26B355}.Prerelease|Any CPU.ActiveCfg = Prerelease|Any CPU
- {011DC646-BEF9-4D3B-9D20-CA444A26B355}.Prerelease|Any CPU.Build.0 = Prerelease|Any CPU
+ {011DC646-BEF9-4D3B-9D20-CA444A26B355}.Prerelease|Any CPU.ActiveCfg = Release|Any CPU
+ {011DC646-BEF9-4D3B-9D20-CA444A26B355}.Prerelease|Any CPU.Build.0 = Release|Any CPU
{011DC646-BEF9-4D3B-9D20-CA444A26B355}.Release|Any CPU.ActiveCfg = Release|Any CPU
{011DC646-BEF9-4D3B-9D20-CA444A26B355}.Release|Any CPU.Build.0 = Release|Any CPU
{863DC1E0-8E93-4EE6-8404-75C34838FF2A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
diff --git a/src/GoogleCAProxy/app.config b/src/GoogleCAProxy/app.config
deleted file mode 100644
index 64579c1..0000000
--- a/src/GoogleCAProxy/app.config
+++ /dev/null
@@ -1,71 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/GoogleCAProxy/packages.config b/src/GoogleCAProxy/packages.config
deleted file mode 100644
index 399f50a..0000000
--- a/src/GoogleCAProxy/packages.config
+++ /dev/null
@@ -1,31 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/GoogleCASandbox/App.config b/src/GoogleCASandbox/App.config
index 271c5b8..bc44800 100644
--- a/src/GoogleCASandbox/App.config
+++ b/src/GoogleCASandbox/App.config
@@ -69,6 +69,14 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/GoogleCASandbox/GoogleCASandbox.csproj b/src/GoogleCASandbox/GoogleCASandbox.csproj
index 5daafcc..b2b35d4 100644
--- a/src/GoogleCASandbox/GoogleCASandbox.csproj
+++ b/src/GoogleCASandbox/GoogleCASandbox.csproj
@@ -8,7 +8,8 @@
Exe
GoogleCASandbox
GoogleCASandbox
- v4.6.2
+ v4.7.2
+ net472
512
true
true
@@ -38,93 +39,21 @@
bin\Prerelease\
-
- ..\GoogleCAProxy\packages\Keyfactor.AnyGateway.SDK.20.9.0\lib\net462\CAProxy.AnyGateway.Core.dll
+
+ ..\packages\Keyfactor.AnyGateway.SDK.21.3.2\lib\net462\CAProxy.AnyGateway.Core.dll
-
- ..\GoogleCAProxy\packages\Keyfactor.AnyGateway.SDK.20.9.0\lib\net462\CAProxy.Interfaces.dll
+
+ ..\packages\Keyfactor.AnyGateway.SDK.21.3.2\lib\net462\CAProxy.Interfaces.dll
-
- ..\GoogleCAProxy\packages\Common.Logging.3.4.1\lib\net40\Common.Logging.dll
+
+ ..\packages\Keyfactor.AnyGateway.SDK.21.3.2\lib\net462\CAProxyDAL.dll
-
- ..\GoogleCAProxy\packages\Common.Logging.Core.3.4.1\lib\net40\Common.Logging.Core.dll
-
-
- ..\GoogleCAProxy\packages\Keyfactor.AnyGateway.SDK.20.9.0\lib\net462\CommonCAProxy.dll
-
-
- ..\GoogleCAProxy\packages\CSS.Common.1.7.0\lib\net462\CSS.Common.dll
-
-
- ..\GoogleCAProxy\packages\Google.Api.CommonProtos.2.2.0\lib\net461\Google.Api.CommonProtos.dll
-
-
- ..\GoogleCAProxy\packages\Google.Api.Gax.3.2.0\lib\net461\Google.Api.Gax.dll
-
-
- ..\GoogleCAProxy\packages\Google.Api.Gax.Grpc.3.2.0\lib\net461\Google.Api.Gax.Grpc.dll
-
-
- ..\GoogleCAProxy\packages\Google.Api.Gax.Grpc.GrpcCore.3.2.0\lib\net461\Google.Api.Gax.Grpc.GrpcCore.dll
-
-
- ..\GoogleCAProxy\packages\Google.Apis.1.49.0\lib\net45\Google.Apis.dll
-
-
- ..\GoogleCAProxy\packages\Google.Apis.Auth.1.49.0\lib\net45\Google.Apis.Auth.dll
-
-
- ..\GoogleCAProxy\packages\Google.Apis.Auth.1.49.0\lib\net45\Google.Apis.Auth.PlatformServices.dll
-
-
- ..\GoogleCAProxy\packages\Google.Apis.Core.1.49.0\lib\net45\Google.Apis.Core.dll
-
-
- ..\GoogleCAProxy\packages\Google.Apis.1.49.0\lib\net45\Google.Apis.PlatformServices.dll
-
-
- ..\GoogleCAProxy\packages\Google.Cloud.Security.PrivateCA.V1Beta1.1.0.0-beta01\lib\net461\Google.Cloud.Security.PrivateCA.V1Beta1.dll
-
-
- ..\GoogleCAProxy\packages\Google.LongRunning.2.1.0\lib\net461\Google.LongRunning.dll
-
-
- ..\GoogleCAProxy\packages\Google.Protobuf.3.14.0\lib\net45\Google.Protobuf.dll
-
-
- ..\GoogleCAProxy\packages\Grpc.Auth.2.34.0\lib\net45\Grpc.Auth.dll
-
-
- ..\GoogleCAProxy\packages\Grpc.Core.2.34.0\lib\net45\Grpc.Core.dll
-
-
- ..\GoogleCAProxy\packages\Grpc.Core.Api.2.34.0\lib\net45\Grpc.Core.Api.dll
-
-
- ..\GoogleCAProxy\packages\Microsoft.Bcl.AsyncInterfaces.5.0.0\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll
-
-
- ..\GoogleCAProxy\packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll
+
+ ..\packages\Keyfactor.AnyGateway.SDK.21.3.2\lib\net462\CAProxy.Interfaces.dll
-
- ..\GoogleCAProxy\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll
-
-
- ..\GoogleCAProxy\packages\System.Memory.4.5.4\lib\net461\System.Memory.dll
-
-
- ..\GoogleCAProxy\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll
-
-
- ..\GoogleCAProxy\packages\System.Runtime.CompilerServices.Unsafe.5.0.0\lib\net45\System.Runtime.CompilerServices.Unsafe.dll
-
-
- ..\GoogleCAProxy\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll
-
@@ -138,7 +67,6 @@
-
@@ -146,16 +74,38 @@
GoogleCAProxy
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
+
+
+
-
-
-
- This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
-
-
-
\ No newline at end of file
diff --git a/src/GoogleCASandbox/Program.cs b/src/GoogleCASandbox/Program.cs
index 14c5d7a..58f00b3 100644
--- a/src/GoogleCASandbox/Program.cs
+++ b/src/GoogleCASandbox/Program.cs
@@ -1,6 +1,4 @@
-using CAProxy.AnyGateway.Interfaces;
-using Google.Cloud.Security.PrivateCA.V1Beta1;
-using Google.Protobuf.WellKnownTypes;
+using Google.Protobuf.WellKnownTypes;
using Keyfactor.AnyGateway.Google;
using System;
using System.Collections;
@@ -10,6 +8,7 @@
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
+using Google.Cloud.Security.PrivateCA.V1;
using Google.Protobuf;
namespace GoogleCASandbox
@@ -18,61 +17,8 @@ class Program
{
static void Main(string[] args)
{
- Environment.SetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS", @"C:\cms\concise-frame-296019-2e104088b76a.json");
-
- CertificateAuthorityServiceClient gcp = CertificateAuthorityServiceClient.Create();
-
- var caName = CertificateAuthorityName.FromProjectLocationCertificateAuthority("concise-frame-296019", "us-east1", "ca-enterprise-subordinate-sandbox-new");
-
- for (int i = 0; i <= 100; i++)
- {
- ByteString publicKey = ByteString.CopyFrom($"MYPUBLICKEY{i}", Encoding.ASCII);
-
-
- DateTime now = DateTime.Now;
- var response = gcp.CreateCertificate(new CreateCertificateRequest()
- {
- CertificateId = $"loadtest-{i}-{now:HH}{now:mm}{now:ss}",
- ParentAsCertificateAuthorityName = caName,
- Certificate = new Certificate()
- {
- Lifetime = Duration.FromTimeSpan(new TimeSpan(1, 0, 0, 0, 0)),
- Config = new CertificateConfig()
- {
- PublicKey = new PublicKey() { Key = publicKey, Type=PublicKey.Types.KeyType.PemRsaKey},
- SubjectConfig = new CertificateConfig.Types.SubjectConfig()
- {
- CommonName = $"loadcert-{now:MMM}-{now:ffffff}"
- }
- }
- }
- });
-
- Console.WriteLine($"Created Load Test Certificate {response.CertificateName.CertificateId}");
- }
- }
-
- static bool CompareFiles(string file1, string file2)
- {
- if (!File.Exists(file1))
- throw new FileNotFoundException($"Cannot find {file1} for comparison");
-
- if (!File.Exists(file2))
- throw new FileNotFoundException($"Cannot find {file2} for comparison");
-
-
- byte[] file1Hash = SHA1.Create().ComputeHash(File.ReadAllBytes(file1));
- byte[] file2Hash = SHA1.Create().ComputeHash(File.ReadAllBytes(file2));
-
- return Convert.ToBase64String(file1Hash).Equals(Convert.ToBase64String(file2Hash));
-
+ Environment.SetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS",
+ @"C:\cms\concise-frame-296019-2e104088b76a.json");
}
}
-
- class ConfigProvider : ICAConnectorConfigProvider
- {
- public Dictionary CAConnectionData { get; set; }
- }
-
-
}
diff --git a/src/GoogleCASandbox/packages.config b/src/GoogleCASandbox/packages.config
deleted file mode 100644
index 4c79bc1..0000000
--- a/src/GoogleCASandbox/packages.config
+++ /dev/null
@@ -1,28 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file