> ## Documentation Index
> Fetch the complete documentation index at: https://docs.certgovernance.app/llms.txt
> Use this file to discover all available pages before exploring further.

# certforge-connector

> Open-source on-premises agent. Automates certificate renewal for network devices on private VLANs — with optional on-prem CA signing governed by Domain Trust Policies.

`certforge-connector` is an open-source agent that automates certificate renewal for network devices — SBCs, voice gateways, load balancers — that live on private management VLANs unreachable by CertForge directly.

GitHub: [CertForge-LLC/certforge-connector](https://github.com/CertForge-LLC/certforge-connector)

## How it works

```
[CertForge cloud] ←── poll every 30s ──── [certforge-connector]
                                                    │
                                         reaches private VLAN
                                                    │
                                     [network device (SBC / F5 / gateway)]
```

The connector is stateless and requires no inbound firewall rules. It polls CertForge for pending renewal jobs, pulls a CSR from the device, has it signed (by CertForge or by your on-prem CA), and installs the certificate back on the device.

**Device credentials are not stored on the connector host.** Username and password are entered in CertForge under **Network Devices**, stored AES-256-GCM encrypted, and delivered to the connector at job execution time — in memory, never written to disk.

## Prerequisites

* A CertForge account with at least one CA configured
* The device registered under **Integrations → Network Devices** in CertForge
* A **connector** API key (see below)
* TCP access from the connector host to the device management IP on its configured port (default 443)

## Step 1 — Create a connector API key

The connector authenticates to CertForge with a scoped API key. These keys can only reach the `/api/v1/connector/` endpoints.

1. Go to **Settings → API Keys**
2. Click **New API Key**
3. Give it a descriptive name (e.g. `office-connector`)
4. Check the **connector** scope
5. Click **Create**
6. Copy the key — it is shown **once only**

Store it in an environment variable, not in the YAML config file:

```sh theme={null}
# Linux / macOS
export CERTFORGE_API_KEY=<your-key>
```

```powershell theme={null}
# Windows (PowerShell)
$env:CERTFORGE_API_KEY = "<your-key>"
```

## Step 2 — Register devices in CertForge

Before the connector can renew a device cert, the device must be registered in CertForge:

1. Go to **Integrations → Network Devices**
2. Click **Register Device**
3. Enter the device's name, management IP, port, device type, and credentials
4. Click **Save**

The device UUID displayed on this page is what the connector uses to match renewal jobs. Once the connector is running, the **Device Type** dropdown is populated automatically from the types the connector reports — no manual entry required.

## Step 3 — Install the connector

### Binary (recommended)

Download the pre-built binary for your platform from the [latest release](https://github.com/CertForge-LLC/certforge-connector/releases/latest):

| Platform            | File                                    |
| ------------------- | --------------------------------------- |
| Linux x86-64        | `certforge-connector-linux-amd64`       |
| Linux ARM64         | `certforge-connector-linux-arm64`       |
| macOS x86-64        | `certforge-connector-darwin-amd64`      |
| macOS Apple Silicon | `certforge-connector-darwin-arm64`      |
| Windows x86-64      | `certforge-connector-windows-amd64.exe` |

```sh theme={null}
# Linux
curl -LO https://github.com/CertForge-LLC/certforge-connector/releases/latest/download/certforge-connector-linux-amd64
chmod +x certforge-connector-linux-amd64
sudo mv certforge-connector-linux-amd64 /usr/local/bin/certforge-connector
```

### Windows

```powershell theme={null}
# Force TLS 1.2 (required on older PowerShell)
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
New-Item -ItemType Directory -Force -Path C:\certforge-connector
Invoke-WebRequest -Uri https://github.com/CertForge-LLC/certforge-connector/releases/latest/download/certforge-connector-windows-amd64.exe `
    -OutFile C:\certforge-connector\certforge-connector.exe
```

### Docker

```sh theme={null}
docker run -d --restart unless-stopped \
  --network host \
  -e CERTFORGE_API_KEY=<your-key> \
  -v /etc/certforge-connector/certforge-connector.yaml:/etc/certforge-connector/certforge-connector.yaml:ro \
  ghcr.io/certforge-llc/certforge-connector:latest
```

`--network host` is required so the connector can reach devices on private management VLANs.

### Azure Container Instances

To reach devices on a private Azure VNet (F5 BIG-IP, Ribbon SBC, etc.), deploy the connector as an Azure Container Instance inside that VNet. No inbound ports are required.

See [Connector in Azure](/guides/connector-azure) for the full step-by-step guide.

## Step 4 — Configure

Create `certforge-connector.yaml` (start from `certforge-connector.yaml.example` in the release):

```yaml theme={null}
# URL of your CertForge instance
certforge_url: https://app.certgovernance.app

# API key from Settings → API Keys (connector scope)
# Always load from an environment variable
api_key: $CERTFORGE_API_KEY

# How often to poll for pending jobs (default 30s)
poll_interval: 30s
```

That's the entire required config. Device topology — host, port, type, and credentials — is stored in CertForge and delivered with each renewal job automatically.

### Local credential override (optional)

If you store device credentials in a local secrets manager rather than in CertForge, you can supply them via the `devices:` block. List one entry per device with the CertForge device UUID, username, and password. All other details come from CertForge automatically.

```yaml theme={null}
devices:
  - id: "00000000-0000-0000-0000-000000000000"  # UUID from CertForge → Network Devices
    username: admin
    password: $SBC1_PASSWORD
  - id: "11111111-1111-1111-1111-111111111111"
    username: admin
    password: $SBC2_PASSWORD
  - id: "22222222-2222-2222-2222-222222222222"
    username: readonly
    password: $F5_PASSWORD
```

Most deployments can omit the `devices:` block entirely.

## Step 5 — Run

**Test (manual):**

```sh theme={null}
# Linux / macOS
CERTFORGE_API_KEY=<your-key> certforge-connector -config certforge-connector.yaml

# Windows
$env:CERTFORGE_API_KEY = "<your-key>"
.\certforge-connector.exe -config .\certforge-connector.yaml
```

**Linux service (systemd):**

```ini theme={null}
[Unit]
Description=CertForge Connector
After=network-online.target
Wants=network-online.target

[Service]
ExecStart=/usr/local/bin/certforge-connector -config /etc/certforge-connector/certforge-connector.yaml
EnvironmentFile=/etc/certforge-connector/env
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target
```

Put the API key in `/etc/certforge-connector/env`:

```sh theme={null}
CERTFORGE_API_KEY=<your-key>
```

**Windows service (NSSM):**

Download [NSSM](https://nssm.cc) and from an elevated command prompt:

```cmd theme={null}
nssm install CertForgeConnector "C:\certforge-connector\certforge-connector.exe"
nssm set CertForgeConnector AppParameters "-config C:\certforge-connector\certforge-connector.yaml"
nssm set CertForgeConnector AppDirectory "C:\certforge-connector"
nssm set CertForgeConnector AppEnvironmentExtra "CERTFORGE_API_KEY=<your-key>"
nssm set CertForgeConnector Start SERVICE_AUTO_START
nssm start CertForgeConnector
```

## What the connector reports

Once running, the connector performs the following automatically:

### Background cert discovery

On startup and every 6 hours, the connector TLS-dials each registered device and reads the leaf certificate — no device credentials needed. It reports the cert's expiry date, Common Name, and SANs back to CertForge.

CertForge uses this to populate the **Expires**, **DTP**, and **Renewal in** columns on the Network Devices page before any renewal job has run.

### On-demand cert query

From the Network Devices page, clicking **Query Cert** creates a `pending_query` job. The connector picks it up on its next poll and immediately reads and reports the current certificate.

### Certificate renewal

When a cert enters its renewal window (configured in the matching Domain Trust Profile), CertForge creates a renewal job:

1. Connector polls `GET /api/v1/connector/jobs` and receives the job with device connection details and credentials
2. Connector authenticates to the device and pulls the CSR
3. CSR is submitted to CertForge; CertForge signs it with the configured CA
4. Connector installs the signed certificate on the device
5. Connector posts job completion; CertForge schedules the next renewal

All steps appear in the CertForge audit log.

## On-prem CA signing (optional)

By default, CSRs are sent to CertForge for signing. If your signing CA is on-prem and you do not want CSRs leaving the network, you can configure the connector to sign locally while still enforcing your Domain Trust Policy through CertForge.

### How governed local signing works

Before signing any certificate, the connector calls CertForge to validate:

* The device's domain matches a Domain Trust Policy
* The DTP is linked to the correct on-prem CA
* Key strength and wildcard policy are satisfied

CertForge records the authorization server-side. If CertForge is unreachable, the connector **will not sign** — it is fail-closed. The signed certificate is reported back to CertForge for audit and inventory.

### Setup

1. Go to **Settings → CA Connectors** and add a **Private / Internal CA (On-Prem Agent)** connector. This automatically creates a CA record in CertForge that can be referenced in Issuance Profiles and Domain Trust Policies.

2. Create an Issuance Profile pointing to this CA, then assign it in a Domain Trust Policy covering your device domains.

3. Add the CA key and certificate to `certforge-connector.yaml`. Use the `ca_connector_id` from the CA connector record in CertForge:

```yaml theme={null}
private_ca:
  cert: /etc/certforge-connector/ca.crt   # PEM CA certificate
  key:  /etc/certforge-connector/ca.key   # PEM CA private key (RSA or ECDSA)
  validity_days: 365                       # fallback; DTP policy takes precedence
  ca_connector_id: 00000000-0000-0000-0000-000000000000  # from CertForge UI
```

<Warning>
  `ca_connector_id` is required. The connector will refuse to start if a `private_ca` or `private_cas` entry is present without a `ca_connector_id`. Every local signing request must be authorized by CertForge (DTP validation, key policy) before the CA key is used — no exceptions.
</Warning>

**CA key security:** the CA private key is loaded from disk on the connector host. Restrict file permissions to the connector process user:

```sh theme={null}
chmod 600 /etc/certforge-connector/ca.key
chown certforge-connector:certforge-connector /etc/certforge-connector/ca.key
```

For higher-assurance environments, consider a passphrase-protected key or loading it from a local secrets manager (HashiCorp Vault, AWS Secrets Manager, etc.).

If you manage multiple on-prem CAs, use `private_cas:` to list them:

```yaml theme={null}
private_cas:
  - ca_connector_id: 00000000-0000-0000-0000-000000000000
    cert: /etc/ca/internal.crt
    key:  /etc/ca/internal.key
  - ca_connector_id: 11111111-1111-1111-1111-111111111111
    cert: /etc/ca/devices.crt
    key:  /etc/ca/devices.key
```

### CA inventory sync

When `ca_connector_id` is set, the connector can also push the CA's issued certificate inventory into CertForge Discovery. Add an inventory source to the `private_ca` block:

**File-based CAs** (OpenSSL, Easy-RSA, cfssl):

```yaml theme={null}
private_ca:
  cert: /etc/certforge-connector/ca.crt
  key:  /etc/certforge-connector/ca.key
  ca_connector_id: 00000000-0000-0000-0000-000000000000
  issued_certs_dir: /etc/pki/CA/newcerts   # directory of PEM cert files
  crl_file: /etc/pki/CA/crl.pem           # optional — revoked certs excluded
```

**HashiCorp Vault PKI:**

```yaml theme={null}
private_ca:
  cert: /etc/certforge-connector/ca.crt
  key:  /etc/certforge-connector/ca.key
  ca_connector_id: 00000000-0000-0000-0000-000000000000
  vault_pki:
    addr: https://vault.example.com
    token: $VAULT_TOKEN
    mount: pki
```

Inventory syncs on startup and every 6 hours. Pushed certs appear in Discovery with `governance_status=tracked`.

## Supported device types

| Type                                  | Driver       |
| ------------------------------------- | ------------ |
| AudioCodes Mediant (VE/E/SW/HW)       | `audiocodes` |
| F5 BIG-IP (iControl REST, TMOS 11.6+) | `f5`         |
| Ribbon SWe-Lite SBC (REST API)        | `ribbon`     |

The **Device Type** dropdown in CertForge is populated automatically from the types the running connector reports — no manual entry and no CertForge update required to support a new driver.

Additional drivers can be added by implementing the `Device` interface. See [Adding a device type](https://github.com/CertForge-LLC/certforge-connector#adding-a-device-type) in the connector README.

## Monitoring connector activity

In CertForge, each device shows:

| Column         | Source                                              |
| -------------- | --------------------------------------------------- |
| **Cert CN**    | Read from the device's current certificate          |
| **DTP**        | Domain Trust Profile matched from the cert's CN     |
| **Expires**    | Certificate notAfter date                           |
| **Renewal in** | Days until the DTP-configured renewal window opens  |
| **Last Seen**  | Timestamp of the connector's most recent touchpoint |
| **Status**     | Active / Inactive (toggled manually)                |

Inactive devices are excluded from connector job lists — the connector will not attempt renewal or query jobs for them.

## Troubleshooting

**Connector connects but devices show no cert data**

* Verify TCP access from the connector host to the device management IP and port
* Check the device is set to **Active** on the Network Devices page
* Run manually (`certforge-connector -config certforge-connector.yaml`) to see log output

**`tls: internal error` on cert read**

The device management interface may use a self-signed certificate. Set `skip_verify: true` in the device registration form in CertForge for that device.

**Jobs are created but never picked up**

The connector polls every `poll_interval` (default 30s). If jobs remain pending after a few cycles, check:

* Connector is running and can reach `app.certgovernance.app`
* API key has the `connector` scope
* Device is set to Active in CertForge

**Renewal completed but cert wasn't installed**

Check the audit log in CertForge for `connector.cert_signed` events. If the CSR was submitted and signed but install failed, the connector log will show the device API error.

**Local signing denied by CertForge**

If you see `local signing denied` in the connector log, check:

* The device domain matches a Domain Trust Policy
* The DTP is linked to the on-prem CA connector record
* The `ca_connector_id` in `certforge-connector.yaml` matches the record in CertForge

**`private CA has no ca_connector_id` at startup**

The connector refuses to start if a `private_ca` or `private_cas` entry lacks `ca_connector_id`. Add the connector record in CertForge (**Settings → CA Connectors**), copy its ID, and add `ca_connector_id: <id>` to the YAML entry. See [On-prem CA signing](#on-prem-ca-signing-optional) above.

## Security

### Firewall / egress requirements

The connector requires **outbound HTTPS (port 443) only** — no inbound ports are needed.

| Destination                                                   | Port            | Required when                      |
| ------------------------------------------------------------- | --------------- | ---------------------------------- |
| `app.certgovernance.app` (US) or `eu.certgovernance.app` (EU) | 443             | Always                             |
| Your Vault address                                            | 443 (or custom) | Only if `vault_pki:` is configured |
| Device management IPs (private VLAN)                          | 443 (default)   | Always — stays on the local VLAN   |

### Local credential overrides

If you supply device credentials via the `devices:` block in YAML (rather than storing them in CertForge), treat this as an advanced, higher-risk configuration:

* Use environment variable expansion (`$SBC1_PASSWORD`) — never hardcode secrets in the file.
* Restrict YAML file permissions (`chmod 600 certforge-connector.yaml`) so only the connector process can read it.
* The preferred path is to store credentials in CertForge, which encrypts them at rest (AES-256-GCM) and delivers them only at job time. YAML overrides are intended for environments where credentials must come from a local secrets manager.

### TLS to devices

`skip_verify: true` disables TLS certificate checking for device management connections. It should only be used when the device uses a self-signed management certificate and you cannot install a trusted CA for it. Surface this prominently in device inventories and plan to replace self-signed management certs where possible.
