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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net6.0;net8.0;net10.0</TargetFrameworks>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>disable</Nullable>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
Expand Down
102 changes: 59 additions & 43 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,26 +47,30 @@ The DLL ships **two validator types**:

When configuring a Domain Validation Configuration in the gateway UI, pick the validator type that matches the CA's requirement — TXT/`dns-01` for ACME, CNAME/`cname` for CAs that validate via CNAME. Both share the same cPanel credentials and configuration fields.

The plugin uses the server-wide [WHM API 1](https://api.docs.cpanel.net/whm/introduction/) with a WHM API token, so a single root or reseller credential can manage every DNS zone the server is authoritative for. Records are read with `dumpzone`, created with `addzonerecord`, removed with `removezonerecord`, and zones are enumerated with `listzones`. For TXT staging, existing values at the same name are preserved and the new value is appended, so co-existing ACME challenges (a wildcard and the apex domain both producing `_acme-challenge` TXT values) coexist. For CNAME staging, any existing CNAME at the name is removed first since a CNAME is singular per name. The owning zone for an FQDN is resolved by selecting the zone whose name is the longest matching suffix of the record name.
The plugin uses the server-wide [WHM API 1](https://api.docs.cpanel.net/whm/introduction/) with a WHM API token, so a single root or reseller credential can manage every DNS zone the server is authoritative for. Records are read with `dumpzone`, created with `addzonerecord`, and removed with `removezonerecord`; zones are enumerated with `listzones`. For TXT staging, existing values at the same name are preserved and the new value is appended, so co-existing ACME challenges (a wildcard and the apex domain both producing `_acme-challenge` TXT values) coexist. For CNAME staging, any existing CNAME at the name is removed first since a CNAME is singular per name by DNS rules. The owning zone for an FQDN is resolved by selecting the zone whose name is the longest matching suffix of the record name.

## Features

- Automated DNS TXT (dns-01) and CNAME (cname) record creation and deletion on cPanel / WHM
- Server-wide management via a single WHM API token (root or reseller)
- Automatic zone discovery by longest zone-name suffix match
- Optional TLS-validation skip for cPanel servers using self-signed certificates
- Automated DNS TXT record creation and deletion in cPanel DNS

## Requirements

### Keyfactor Platform
- Keyfactor AnyCA Gateway REST **26.2 or later** (DNS validation support was added in AnyCA Gateway 26.2)
- A gateway product that supports DNS-01 domain validation (ACME REST Gateway, DigiCert, Sectigo, etc.)

### cPanel DNS Requirements

### Keyfactor platform

- Keyfactor AnyCA Gateway REST **26.2 or later** (DNS validation support was added in AnyCA Gateway 26.2)
- A gateway product that supports DNS-based domain validation (ACME REST Gateway, DigiCert, Sectigo, SSL Store, etc.)

### cPanel / WHM Requirements
### cPanel / WHM requirements

1. A cPanel & WHM server that is **authoritative** for the domains being validated (the domain's nameservers delegate to this server). If DNS is hosted elsewhere, records created here will not be resolvable by the CA.
2. A **WHM API token** (WHM » Development » Manage API Tokens) owned by `root` or a reseller, with privileges to read and edit DNS zones.
3. Network reachability from the gateway host to the WHM port (**2087/tcp**).
1. A cPanel & WHM server that is **authoritative** for the domains being validated (the domain's nameservers delegate to this server). If DNS for the domain is hosted elsewhere, records created here will not be resolvable by the CA.
2. A **WHM API token** (WHM » Development » Manage API Tokens) owned by `root` or a reseller, with privileges to read and edit DNS zones (`listzones`, `dumpzone`, `addzonerecord`, `removezonerecord`).
3. Network reachability from the gateway host to the WHM port (**2087/tcp**) on the cPanel server.

### Configuration fields

Expand All @@ -75,76 +79,72 @@ The plugin uses the server-wide [WHM API 1](https://api.docs.cpanel.net/whm/intr
| `CPanel_BaseUrl` | Yes | Base URL of the cPanel/WHM server including the WHM port, e.g. `https://host.example.com:2087`. |
| `CPanel_Username` | Yes | WHM user that owns the API token (typically `root`). |
| `CPanel_ApiToken` | Yes | WHM API token with DNS zone privileges. Stored as a secret. |
| `CPanel_SkipTlsValidation` | No | Set to `true` to skip TLS validation for a self-signed server certificate. Defaults to `false`. |
| `CPanel_SkipTlsValidation` | No | Set to `true` to skip TLS certificate validation when the server uses a self-signed certificate. Defaults to `false`. |

### Notes and limitations

* The plugin sets the record TTL to 300 seconds.
* Records are managed via the **server-wide WHM API 1**; the token must belong to `root` or a reseller with DNS zone privileges. A per-account cPanel UAPI mode is not implemented in this release.
* Zones are discovered from the server's `listzones` output; a record whose domain is not covered by a zone on the server fails with `No cPanel DNS zone found`.
* Record removal uses `dumpzone` line numbers; the plugin deletes matched lines in descending order within one `dumpzone` snapshot to stay correct as WHM re-indexes records.
* Each validator type manages only its own record type: `CPanelDomainValidator` reads/writes `TXT`, `CPanelCnameDomainValidator` reads/writes `CNAME`.
* Record removal uses `dumpzone` line numbers; because WHM re-indexes records after each deletion, the plugin removes matched lines in descending order within a single `dumpzone` snapshot.
* Each validator type manages only its own record type: `CPanelDomainValidator` reads/writes `TXT`, `CPanelCnameDomainValidator` reads/writes `CNAME`. Neither touches other record types.

### Runtime Requirements
- .NET runtime provided by the gateway server (the plugin targets net6.0, net8.0, and net10.0)
- .NET 10.0 runtime (provided by the gateway server)

## Installation

This plugin is installed alongside any Keyfactor gateway server that supports DNS-based domain validation (ACME REST Gateway, DigiCert, Sectigo, SSL Store, etc.). The same DLL works with every supported gateway.
This plugin is installed alongside any Keyfactor gateway server that supports DNS-01 domain validation (ACME REST Gateway, DigiCert, Sectigo, etc.). The same DLL works with every supported gateway.

> See the official Keyfactor AnyCA Gateway REST installation documentation for the authoritative install instructions. The steps below are a general guide; defer to the official docs if they diverge.
> See the official Keyfactor AnyCA Gateway REST installation documentation for the authoritative install instructions: **<TBD link from Sarah Duncan>**. The steps below are a general guide; defer to the official docs if they diverge.

### 1. Download the Plugin

Download the latest release from the [Releases](https://github.com/Keyfactor/cpanel-dnsplugin/releases) page.

### 2. Copy the plugin DLLs to the gateway's Extensions folder

On the server hosting your gateway, unzip the release and copy the contents of the framework directory that matches your gateway (e.g. `net8.0`) into the gateway's `Extensions` folder.
On the server hosting your gateway, unzip the release and copy the contents of the `net10.0` directory into the gateway's `Extensions` folder.

**Windows** (example path — substitute the gateway product folder for your install):

```text
C:\Program Files\Keyfactor\<GatewayName>\AnyGatewayREST\net8.0\Extensions\
C:\Program Files\Keyfactor\<GatewayName>\AnyGatewayREST\net10.0\Extensions\
```

**Linux**:

```text
/opt/keyfactor/<gateway-name>/AnyGatewayREST/net8.0/Extensions/
/opt/keyfactor/<gateway-name>/AnyGatewayREST/net10.0/Extensions/
```

Replace `<GatewayName>` (or `<gateway-name>` on Linux) with the gateway you are installing into (e.g. `AcmeGwDns`, `DigiCert`, `Sectigo`, `SslStoreGw`).
Replace `<GatewayName>` (or `<gateway-name>` on Linux) with the gateway you are installing into (e.g. `AcmeGwDns`, `DigiCert`, `Sectigo`).

### 3. Restart the gateway service

Restart the AnyGatewayREST service for the gateway you installed the plugin into so the Extensions folder is rescanned.
Restart the AnyGatewayREST Windows service for the gateway you installed the plugin into so the Extensions folder is rescanned.

## Configuration

After installing the plugin DLL into the gateway's Extensions folder, configure a new Domain Validation entry in the AnyCA Gateway REST UI and select **cPanel DNS** (`CPanelDomainValidator` for TXT/dns-01, or `CPanelCnameDomainValidator` for CNAME) as the provider type, then map it to the domain(s) it should manage.

### Creating a WHM API token

In WHM, go to **Development » Manage API Tokens**, click **Generate Token**, name it (e.g. `keyfactor-dns`), grant DNS zone privileges (or full access for testing), and copy the token — it is shown only once.
After installing the plugin DLL into the gateway's Extensions folder, configure a new DNS Provider entry in the AnyCA Gateway REST UI and select **cPanel** as the provider type. See the official Keyfactor AnyCA Gateway REST documentation for the canonical UI walkthrough: **<TBD link from Sarah Duncan>**.

### Configuration Parameters

| Parameter | Description | Required | Example |
|-----------|-------------|----------|---------|
| `CPanel_BaseUrl` | Base URL of the cPanel/WHM server including the WHM port. | Yes | `https://host.example.com:2087` |
| `CPanel_Username` | WHM user that owns the API token. | Yes | `root` |
| `CPanel_ApiToken` | WHM API token (stored as a secret). | Yes | ` ` |
| `CPanel_SkipTlsValidation` | Skip TLS validation for a self-signed certificate. | No | `false` |
| `CPanel_BaseUrl` | Base URL of the cPanel/WHM server including the WHM port, e.g. https://host.example.com:2087. | Yes | ` ` |
| `CPanel_Username` | WHM user that owns the API token (typically 'root' or a reseller account). | Yes | `root` |
| `CPanel_ApiToken` | WHM API token with DNS zone privileges. Stored as a secret. | Yes | ` ` |
| `CPanel_SkipTlsValidation` | Set to 'true' to skip TLS certificate validation when the cPanel server uses a self-signed certificate. Defaults to false. | No | `false` |

### Example Configuration

```json
{
"CPanel_BaseUrl": "https://host.example.com:2087",
"CPanel_Username": "root",
"CPanel_ApiToken": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"CPanel_SkipTlsValidation": "false"
"CPanel_BaseUrl": "",
"CPanel_Username": "",
"CPanel_ApiToken": "",
"CPanel_SkipTlsValidation": ""
}
```

Expand All @@ -154,25 +154,41 @@ In WHM, go to **Development » Manage API Tokens**, click **Generate Token**, na

Once configured, the plugin automatically handles DNS validation during certificate enrollment and renewal:

1. **Record Creation**: the gateway calls the plugin to publish the validation record (TXT or CNAME) in the appropriate cPanel DNS zone.
2. **Validation**: the CA verifies the record and issues the certificate.
3. **Cleanup**: the gateway calls the plugin to remove the validation record once the order is issued.
1. **Record Creation**: Plugin creates a DNS TXT record with the validation challenge
2. **Propagation Wait**: Plugin waits for DNS propagation
3. **Verification**: Plugin verifies the record exists on cPanel DNS nameservers
4. **Cleanup**: Plugin deletes the validation record after successful validation

### Zone Discovery

The plugin discovers the zone for a domain by longest matching zone-name suffix among the server's zones:
The plugin automatically discovers the appropriate DNS zone for a domain:

- For `_acme-challenge.www.example.com`, a zone for `example.com` is matched.
- For `*.example.com`, the `example.com` zone is matched.
- For `www.example.com`, searches for zones: `www.example.com`, `example.com`
- For `sub.example.com`, searches for zones: `sub.example.com`, `example.com`
- For `*.example.com`, searches for zones: `example.com`

## Troubleshooting

### Common Issues

- **Authentication Failures**: verify the WHM API token is valid, owned by the configured user, and has DNS zone privileges.
- **Connection Failures**: confirm the gateway host can reach the WHM port (2087/tcp) and that `CPanel_BaseUrl` includes the scheme and port.
- **TLS Errors**: if the cPanel server uses a self-signed certificate, set `CPanel_SkipTlsValidation` to `true` (or install a trusted certificate).
- **Zone Not Found**: verify the target domain is covered by a DNS zone the cPanel server is authoritative for.
- **Authentication Failures**: Verify cPanel DNS credentials are valid, not expired, and authorized for the target zone.
- **Insufficient Permissions**: Verify the account/role has the documented minimum permissions on the target DNS zone.
- **Zone Not Found**: Verify the target DNS zone exists in your cPanel DNS account and is reachable from the gateway server.
- **DNS Propagation Timeouts**: Check cPanel DNS service health; verify authoritative nameservers are responding.

### Logging

Enable debug logging in the gateway's logging configuration:

```json
{
"Logging": {
"LogLevel": {
"Keyfactor.Extensions.DomainValidator.CPanel": "Debug"
}
}
}
```

## Support

Expand Down