feat: complete DNS provider implementation verification
- Verify backend test coverage at 85.2% (threshold: 85%) - Verify frontend test coverage at 87.8% (threshold: 85%) - Add Google Cloud DNS setup guide - Add Azure DNS setup guide - Pass all security scans (Trivy, govulncheck) - Pass all pre-commit hooks
This commit is contained in:
1
.github/agents/QA_Security.agent.md
vendored
1
.github/agents/QA_Security.agent.md
vendored
@@ -75,6 +75,7 @@ The task is not complete until ALL of the following pass with zero issues:
|
||||
- Zero Critical/High issues allowed
|
||||
|
||||
2. **Coverage Tests (MANDATORY - Run Explicitly)**:
|
||||
- **MANDATORY**: Patch coverage must cover 100% of new/modified code. This prevents CodeCov Report failing CI.
|
||||
- **Backend**: Run VS Code task "Test: Backend with Coverage" or execute `scripts/go-test-coverage.sh`
|
||||
- **Frontend**: Run VS Code task "Test: Frontend with Coverage" or execute `scripts/frontend-test-coverage.sh`
|
||||
- **Why**: These are in manual stage of pre-commit for performance. You MUST run them via VS Code tasks or scripts.
|
||||
|
||||
1
.github/instructions/copilot-instructions.md
vendored
1
.github/instructions/copilot-instructions.md
vendored
@@ -108,6 +108,7 @@ Before marking an implementation task as complete, perform the following in orde
|
||||
- Do not output code that violates pre-commit standards.
|
||||
|
||||
3. **Coverage Testing** (MANDATORY - Non-negotiable):
|
||||
- **MANDATORY**: Patch coverage must cover 100% of new/modified code. This prevents CodeCov Report failing CI.
|
||||
- **Backend Changes**: Run the VS Code task "Test: Backend with Coverage" or execute `scripts/go-test-coverage.sh`.
|
||||
- Minimum coverage: 85% (set via `CHARON_MIN_COVERAGE` or `CPM_MIN_COVERAGE`).
|
||||
- If coverage drops below threshold, write additional tests to restore coverage.
|
||||
|
||||
369
docs/guides/dns-providers/azure-dns.md
Normal file
369
docs/guides/dns-providers/azure-dns.md
Normal file
@@ -0,0 +1,369 @@
|
||||
````markdown
|
||||
# Azure DNS Provider Setup
|
||||
|
||||
## Overview
|
||||
|
||||
Azure DNS is Microsoft's cloud-based DNS hosting service that provides name resolution using Microsoft Azure infrastructure. This guide covers setting up Azure DNS as a provider in Charon for wildcard certificate management.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Azure subscription (pay-as-you-go or Enterprise Agreement)
|
||||
- Azure DNS zone created for your domain
|
||||
- Domain nameservers pointing to Azure DNS
|
||||
- Permissions to create App registrations in Microsoft Entra ID (Azure AD)
|
||||
- Permissions to assign roles in Azure RBAC
|
||||
|
||||
## Step 1: Gather Azure Subscription Information
|
||||
|
||||
1. Log in to the [Azure Portal](https://portal.azure.com/)
|
||||
2. Navigate to **Subscriptions**
|
||||
3. Note your **Subscription ID** (e.g., `12345678-1234-1234-1234-123456789abc`)
|
||||
4. Navigate to **Resource groups**
|
||||
5. Note the **Resource group name** containing your DNS zone
|
||||
|
||||
> **Tip:** You can find this information in the DNS zone overview page as well.
|
||||
|
||||
## Step 2: Verify DNS Zone Configuration
|
||||
|
||||
Ensure your domain is properly configured in Azure DNS:
|
||||
|
||||
1. Navigate to **DNS zones**
|
||||
2. Select your DNS zone
|
||||
3. Note the **Azure nameservers** listed (typically 4 servers like `ns1-01.azure-dns.com`)
|
||||
4. Verify your domain registrar is configured to use these nameservers
|
||||
|
||||
<!-- Screenshot placeholder: Azure DNS zone overview showing nameservers -->
|
||||
|
||||
## Step 3: Create App Registration in Microsoft Entra ID
|
||||
|
||||
Create an application identity for Charon:
|
||||
|
||||
1. Navigate to **Microsoft Entra ID** (formerly Azure Active Directory)
|
||||
2. Select **App registrations** from the left menu
|
||||
3. Click **New registration**
|
||||
4. Configure the application:
|
||||
- **Name:** `charon-dns-challenge`
|
||||
- **Supported account types:** Select **Accounts in this organizational directory only**
|
||||
- **Redirect URI:** Leave blank (not needed for service-to-service auth)
|
||||
5. Click **Register**
|
||||
|
||||
### Note Application Details
|
||||
|
||||
After registration, note the following from the **Overview** page:
|
||||
|
||||
- **Application (client) ID:** `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`
|
||||
- **Directory (tenant) ID:** `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`
|
||||
|
||||
<!-- Screenshot placeholder: App registration overview showing client and tenant IDs -->
|
||||
|
||||
## Step 4: Create Client Secret
|
||||
|
||||
1. In your app registration, navigate to **Certificates & secrets**
|
||||
2. Click **New client secret**
|
||||
3. Configure the secret:
|
||||
- **Description:** `Charon DNS Challenge`
|
||||
- **Expires:** Choose an expiration period (recommended: 12 months or 24 months)
|
||||
4. Click **Add**
|
||||
5. **Copy the secret value immediately** (shown only once)
|
||||
|
||||
> **Warning:** The client secret value is displayed only once. Copy it now and store it securely. If you lose it, you'll need to create a new secret.
|
||||
|
||||
### Secret Expiration Management
|
||||
|
||||
| Expiration | Use Case |
|
||||
|------------|----------|
|
||||
| 6 months | Development/testing environments |
|
||||
| 12 months | Production with regular rotation schedule |
|
||||
| 24 months | Production with less frequent rotation |
|
||||
| Custom | Enterprise requirements |
|
||||
|
||||
## Step 5: Assign DNS Zone Contributor Role
|
||||
|
||||
Grant the app registration permission to manage DNS records:
|
||||
|
||||
1. Navigate to your **DNS zone**
|
||||
2. Select **Access control (IAM)** from the left menu
|
||||
3. Click **Add** → **Add role assignment**
|
||||
4. In the **Role** tab:
|
||||
- Search for **DNS Zone Contributor**
|
||||
- Select **DNS Zone Contributor**
|
||||
- Click **Next**
|
||||
5. In the **Members** tab:
|
||||
- Select **User, group, or service principal**
|
||||
- Click **Select members**
|
||||
- Search for `charon-dns-challenge`
|
||||
- Select the app registration
|
||||
- Click **Select**
|
||||
6. Click **Review + assign**
|
||||
7. Click **Review + assign** again to confirm
|
||||
|
||||
> **Note:** Role assignments may take a few minutes to propagate.
|
||||
|
||||
### Required Permissions
|
||||
|
||||
The **DNS Zone Contributor** role includes:
|
||||
|
||||
| Permission | Purpose |
|
||||
|------------|---------|
|
||||
| `Microsoft.Network/dnsZones/read` | Read DNS zone configuration |
|
||||
| `Microsoft.Network/dnsZones/TXT/read` | Read TXT records |
|
||||
| `Microsoft.Network/dnsZones/TXT/write` | Create/update TXT records |
|
||||
| `Microsoft.Network/dnsZones/TXT/delete` | Delete TXT records |
|
||||
| `Microsoft.Network/dnsZones/recordsets/read` | List DNS record sets |
|
||||
|
||||
> **Security Note:** For tighter security, you can create a custom role with only the permissions listed above.
|
||||
|
||||
## Step 6: Configure in Charon
|
||||
|
||||
1. Navigate to **DNS Providers** in Charon
|
||||
2. Click **Add Provider**
|
||||
3. Fill in the form:
|
||||
- **Provider Type:** Select `Azure DNS`
|
||||
- **Name:** Enter a descriptive name (e.g., "Azure DNS - Production")
|
||||
- **Tenant ID:** Paste the Directory (tenant) ID from Step 3
|
||||
- **Client ID:** Paste the Application (client) ID from Step 3
|
||||
- **Client Secret:** Paste the secret value from Step 4
|
||||
- **Subscription ID:** Paste the Subscription ID from Step 1
|
||||
- **Resource Group:** Enter the resource group name containing your DNS zone
|
||||
|
||||
### Configuration Fields Summary
|
||||
|
||||
| Field | Description | Example |
|
||||
|-------|-------------|---------|
|
||||
| **Tenant ID** | Microsoft Entra ID tenant identifier | `12345678-1234-5678-9abc-123456789abc` |
|
||||
| **Client ID** | App registration application ID | `abcdef12-3456-7890-abcd-ef1234567890` |
|
||||
| **Client Secret** | App registration secret value | `abc123~XYZ...` |
|
||||
| **Subscription ID** | Azure subscription identifier | `98765432-1234-5678-9abc-987654321abc` |
|
||||
| **Resource Group** | Resource group containing DNS zone | `rg-dns-production` |
|
||||
|
||||
### Advanced Settings (Optional)
|
||||
|
||||
Expand **Advanced Settings** to customize:
|
||||
|
||||
- **Propagation Timeout:** `120` seconds (Azure DNS propagates quickly)
|
||||
- **Polling Interval:** `10` seconds (default)
|
||||
- **Set as Default:** Enable if this is your primary DNS provider
|
||||
|
||||
## Step 7: Test Connection
|
||||
|
||||
1. Click **Test Connection** button
|
||||
2. Wait for validation (usually 5-10 seconds)
|
||||
3. Verify you see: ✅ **Connection successful**
|
||||
|
||||
The test verifies:
|
||||
- Credentials are valid
|
||||
- App registration has required permissions
|
||||
- DNS zone is accessible
|
||||
- Azure DNS API is reachable
|
||||
|
||||
If the test fails, see [Troubleshooting](#troubleshooting) below.
|
||||
|
||||
## Step 8: Save Configuration
|
||||
|
||||
Click **Save** to store the DNS provider configuration. All credentials are encrypted at rest using AES-256-GCM.
|
||||
|
||||
## Step 9: Use with Wildcard Certificates
|
||||
|
||||
When creating a proxy host with a wildcard domain:
|
||||
|
||||
1. Navigate to **Proxy Hosts** → **Add Proxy Host**
|
||||
2. Enter a wildcard domain: `*.example.com`
|
||||
3. Select **Azure DNS** from the DNS Provider dropdown
|
||||
4. Configure remaining settings
|
||||
5. Save
|
||||
|
||||
Charon will automatically obtain a wildcard certificate using DNS-01 challenge.
|
||||
|
||||
## Example Configuration
|
||||
|
||||
```yaml
|
||||
Provider Type: azure
|
||||
Name: Azure DNS - example.com
|
||||
Tenant ID: 12345678-1234-5678-9abc-123456789abc
|
||||
Client ID: abcdef12-3456-7890-abcd-ef1234567890
|
||||
Client Secret: ****************************************
|
||||
Subscription ID: 98765432-1234-5678-9abc-987654321abc
|
||||
Resource Group: rg-dns-production
|
||||
Propagation Timeout: 120 seconds
|
||||
Polling Interval: 10 seconds
|
||||
Default: Yes
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Connection Test Fails
|
||||
|
||||
**Error:** `Invalid credentials` or `AADSTS7000215: Invalid client secret`
|
||||
|
||||
- Verify the client secret was copied correctly
|
||||
- Check the secret hasn't expired
|
||||
- Ensure no extra whitespace was added
|
||||
- Create a new client secret if necessary
|
||||
|
||||
**Error:** `AADSTS700016: Application not found`
|
||||
|
||||
- Verify the Client ID is correct
|
||||
- Ensure the app registration exists in the correct tenant
|
||||
- Check the Tenant ID matches your organization
|
||||
|
||||
**Error:** `AADSTS90002: Tenant not found`
|
||||
|
||||
- Verify the Tenant ID is correct
|
||||
- Ensure you're using the correct Azure environment (public vs. government)
|
||||
|
||||
**Error:** `Authorization failed` or `Forbidden`
|
||||
|
||||
- Verify the DNS Zone Contributor role is assigned
|
||||
- Check the role is assigned at the DNS zone level
|
||||
- Wait a few minutes for role assignment propagation
|
||||
- Verify the resource group name is correct
|
||||
|
||||
**Error:** `Resource group not found`
|
||||
|
||||
- Check the resource group name spelling (case-sensitive)
|
||||
- Ensure the resource group exists in the specified subscription
|
||||
- Verify the subscription ID is correct
|
||||
|
||||
**Error:** `DNS zone not found`
|
||||
|
||||
- Verify the DNS zone exists in the resource group
|
||||
- Check the domain matches the DNS zone name
|
||||
- Ensure the app has access to the subscription
|
||||
|
||||
### Certificate Issuance Fails
|
||||
|
||||
**Error:** `DNS propagation timeout`
|
||||
|
||||
- Azure DNS typically propagates in 30-60 seconds
|
||||
- Increase Propagation Timeout to 180 seconds
|
||||
- Verify nameservers are correctly configured with your registrar
|
||||
- Check Azure Status page for service issues
|
||||
|
||||
**Error:** `Record creation failed`
|
||||
|
||||
- Verify app registration has DNS Zone Contributor role
|
||||
- Check for existing `_acme-challenge` TXT records that may conflict
|
||||
- Review Charon logs for detailed API errors
|
||||
|
||||
**Error:** `Rate limit exceeded`
|
||||
|
||||
- Azure DNS has API rate limits per subscription
|
||||
- Increase Polling Interval to reduce API calls
|
||||
- Contact Azure support to increase limits if needed
|
||||
|
||||
### Nameserver Propagation
|
||||
|
||||
**Issue:** DNS changes not visible globally
|
||||
|
||||
- Nameserver changes can take 24-48 hours to propagate
|
||||
- Use [DNS Checker](https://dnschecker.org/) to verify global propagation
|
||||
- Verify your registrar shows Azure DNS nameservers
|
||||
- Wait for full propagation before attempting certificate issuance
|
||||
|
||||
### Client Secret Expiration
|
||||
|
||||
**Issue:** Certificates stop renewing
|
||||
|
||||
- Client secrets have expiration dates
|
||||
- Set calendar reminders before expiration
|
||||
- Create new secret and update Charon configuration before expiry
|
||||
- Consider using Managed Identities for Azure-hosted Charon deployments
|
||||
|
||||
## Security Recommendations
|
||||
|
||||
1. **Dedicated App Registration:** Create a separate app registration for Charon
|
||||
2. **Least Privilege:** Use DNS Zone Contributor role (not broader roles)
|
||||
3. **Secret Rotation:** Rotate client secrets before expiration (every 6-12 months)
|
||||
4. **Conditional Access:** Consider conditional access policies for the app
|
||||
5. **Audit Logging:** Enable Azure Activity Log for DNS operations
|
||||
6. **Private Endpoints:** Use private endpoints if Charon runs in Azure
|
||||
7. **Managed Identity:** Use Managed Identity if Charon is hosted in Azure (eliminates secrets)
|
||||
8. **Monitor Sign-ins:** Review app sign-in logs in Microsoft Entra ID
|
||||
|
||||
## Client Secret Rotation
|
||||
|
||||
To rotate the client secret:
|
||||
|
||||
1. Navigate to your app registration → **Certificates & secrets**
|
||||
2. Create a new client secret
|
||||
3. Update the configuration in Charon with the new secret
|
||||
4. Test the connection to verify the new secret works
|
||||
5. Delete the old secret from the Azure portal
|
||||
|
||||
> **Best Practice:** Create the new secret before the old one expires to avoid downtime.
|
||||
|
||||
## Using Azure CLI for Verification (Optional)
|
||||
|
||||
Test configuration before adding to Charon:
|
||||
|
||||
```bash
|
||||
# Login with service principal
|
||||
az login --service-principal \
|
||||
--username CLIENT_ID \
|
||||
--password CLIENT_SECRET \
|
||||
--tenant TENANT_ID
|
||||
|
||||
# Set subscription
|
||||
az account set --subscription SUBSCRIPTION_ID
|
||||
|
||||
# List DNS zones
|
||||
az network dns zone list \
|
||||
--resource-group RESOURCE_GROUP_NAME
|
||||
|
||||
# Test record creation
|
||||
az network dns record-set txt add-record \
|
||||
--resource-group RESOURCE_GROUP_NAME \
|
||||
--zone-name example.com \
|
||||
--record-set-name _acme-challenge-test \
|
||||
--value "test-value"
|
||||
|
||||
# Clean up test record
|
||||
az network dns record-set txt remove-record \
|
||||
--resource-group RESOURCE_GROUP_NAME \
|
||||
--zone-name example.com \
|
||||
--record-set-name _acme-challenge-test \
|
||||
--value "test-value"
|
||||
```
|
||||
|
||||
## Using Managed Identity (Azure-Hosted Charon)
|
||||
|
||||
If Charon runs in Azure (VM, Container Instance, AKS), consider using Managed Identity:
|
||||
|
||||
1. Enable System-assigned managed identity on your Azure resource
|
||||
2. Assign **DNS Zone Contributor** role to the managed identity
|
||||
3. Configure Charon to use managed identity authentication (no secrets needed)
|
||||
|
||||
> **Benefits:** No client secrets to manage, automatic credential rotation, enhanced security.
|
||||
|
||||
## Azure DNS Limitations
|
||||
|
||||
- **Zone-scoped permissions only:** Cannot restrict to specific record types within a zone
|
||||
- **No private DNS support:** Charon requires public DNS for ACME challenges
|
||||
- **Regional availability:** Azure DNS is a global service, no regional selection needed
|
||||
- **Billing:** Azure DNS charges per zone and per million queries
|
||||
|
||||
## Cost Considerations
|
||||
|
||||
Azure DNS pricing (approximate):
|
||||
|
||||
- **Hosted zones:** ~$0.50/month per zone
|
||||
- **DNS queries:** ~$0.40 per million queries
|
||||
|
||||
Certificate challenges generate minimal queries (<100 per certificate issuance).
|
||||
|
||||
## Additional Resources
|
||||
|
||||
- [Azure DNS Documentation](https://learn.microsoft.com/en-us/azure/dns/)
|
||||
- [Microsoft Entra ID App Registration](https://learn.microsoft.com/en-us/entra/identity-platform/quickstart-register-app)
|
||||
- [Azure RBAC for DNS](https://learn.microsoft.com/en-us/azure/dns/dns-protect-zones-recordsets)
|
||||
- [Caddy Azure DNS Module](https://caddyserver.com/docs/modules/dns.providers.azure)
|
||||
- [Azure Status Page](https://status.azure.com/)
|
||||
- [Azure CLI DNS Commands](https://learn.microsoft.com/en-us/cli/azure/network/dns)
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [DNS Providers Overview](../dns-providers.md)
|
||||
- [Wildcard Certificates Guide](../certificates.md#wildcard-certificates)
|
||||
- [DNS Challenges Troubleshooting](../../troubleshooting/dns-challenges.md)
|
||||
|
||||
````
|
||||
327
docs/guides/dns-providers/google-cloud-dns.md
Normal file
327
docs/guides/dns-providers/google-cloud-dns.md
Normal file
@@ -0,0 +1,327 @@
|
||||
````markdown
|
||||
# Google Cloud DNS Provider Setup
|
||||
|
||||
## Overview
|
||||
|
||||
Google Cloud DNS is a high-performance, scalable DNS service built on Google's global infrastructure. This guide covers setting up Google Cloud DNS as a provider in Charon for wildcard certificate management.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Google Cloud Platform (GCP) account
|
||||
- GCP project with billing enabled
|
||||
- Cloud DNS API enabled
|
||||
- DNS zone created in Cloud DNS
|
||||
- Domain nameservers pointing to Google Cloud DNS
|
||||
|
||||
## Step 1: Enable Cloud DNS API
|
||||
|
||||
1. Go to the [Google Cloud Console](https://console.cloud.google.com/)
|
||||
2. Select your project (or create a new one)
|
||||
3. Navigate to **APIs & Services** → **Library**
|
||||
4. Search for **Cloud DNS API**
|
||||
5. Click **Enable**
|
||||
|
||||
> **Note:** The API may take a few minutes to activate after enabling.
|
||||
|
||||
## Step 2: Create a Service Account
|
||||
|
||||
Create a dedicated service account for Charon with minimal permissions:
|
||||
|
||||
1. Navigate to **IAM & Admin** → **Service Accounts**
|
||||
2. Click **Create Service Account**
|
||||
3. Configure the service account:
|
||||
- **Service account name:** `charon-dns-challenge`
|
||||
- **Service account ID:** `charon-dns-challenge` (auto-filled)
|
||||
- **Description:** `Service account for Charon DNS-01 ACME challenges`
|
||||
4. Click **Create and Continue**
|
||||
|
||||
## Step 3: Assign DNS Admin Role
|
||||
|
||||
1. In the **Grant this service account access to project** section:
|
||||
- Click **Select a role**
|
||||
- Search for **DNS Administrator**
|
||||
- Select **DNS Administrator** (`roles/dns.admin`)
|
||||
2. Click **Continue**
|
||||
3. Skip the optional **Grant users access** section
|
||||
4. Click **Done**
|
||||
|
||||
> **Security Note:** For production environments, consider creating a custom role with only the specific permissions needed:
|
||||
> - `dns.changes.create`
|
||||
> - `dns.changes.get`
|
||||
> - `dns.managedZones.list`
|
||||
> - `dns.resourceRecordSets.create`
|
||||
> - `dns.resourceRecordSets.delete`
|
||||
> - `dns.resourceRecordSets.list`
|
||||
> - `dns.resourceRecordSets.update`
|
||||
|
||||
## Step 4: Generate Service Account Key
|
||||
|
||||
1. Click on the newly created service account
|
||||
2. Navigate to the **Keys** tab
|
||||
3. Click **Add Key** → **Create new key**
|
||||
4. Select **JSON** format
|
||||
5. Click **Create**
|
||||
6. **Save the downloaded JSON file securely** (shown only once)
|
||||
|
||||
> **Warning:** The JSON key file contains sensitive credentials. Store it in a password manager or secure vault. Never commit it to version control.
|
||||
|
||||
### Example JSON Key Structure
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "service_account",
|
||||
"project_id": "your-project-id",
|
||||
"private_key_id": "key-id",
|
||||
"private_key": "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n",
|
||||
"client_email": "charon-dns-challenge@your-project-id.iam.gserviceaccount.com",
|
||||
"client_id": "123456789012345678901",
|
||||
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
|
||||
"token_uri": "https://oauth2.googleapis.com/token",
|
||||
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
|
||||
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/..."
|
||||
}
|
||||
```
|
||||
|
||||
## Step 5: Verify DNS Zone Configuration
|
||||
|
||||
Ensure your domain is properly configured in Cloud DNS:
|
||||
|
||||
1. Navigate to **Network services** → **Cloud DNS**
|
||||
2. Verify your zone is listed and active
|
||||
3. Note the **Zone name** (not the DNS name)
|
||||
4. Confirm nameservers are correctly assigned:
|
||||
- `ns-cloud-a1.googledomains.com`
|
||||
- `ns-cloud-a2.googledomains.com`
|
||||
- `ns-cloud-a3.googledomains.com`
|
||||
- `ns-cloud-a4.googledomains.com`
|
||||
|
||||
> **Important:** Update your domain registrar to use Google Cloud DNS nameservers if not already configured.
|
||||
|
||||
## Step 6: Configure in Charon
|
||||
|
||||
1. Navigate to **DNS Providers** in Charon
|
||||
2. Click **Add Provider**
|
||||
3. Fill in the form:
|
||||
- **Provider Type:** Select `Google Cloud DNS`
|
||||
- **Name:** Enter a descriptive name (e.g., "GCP Cloud DNS - Production")
|
||||
- **Project ID:** Enter your GCP project ID (e.g., `my-project-123456`)
|
||||
- **Service Account JSON:** Paste the entire contents of the downloaded JSON key file
|
||||
|
||||
### Advanced Settings (Optional)
|
||||
|
||||
Expand **Advanced Settings** to customize:
|
||||
|
||||
- **Propagation Timeout:** `120` seconds (Cloud DNS propagation is typically fast)
|
||||
- **Polling Interval:** `10` seconds (default)
|
||||
- **Set as Default:** Enable if this is your primary DNS provider
|
||||
|
||||
## Step 7: Test Connection
|
||||
|
||||
1. Click **Test Connection** button
|
||||
2. Wait for validation (usually 5-10 seconds)
|
||||
3. Verify you see: ✅ **Connection successful**
|
||||
|
||||
The test verifies:
|
||||
- Service account credentials are valid
|
||||
- Project ID matches the credentials
|
||||
- Service account has required permissions
|
||||
- Cloud DNS API is accessible
|
||||
|
||||
If the test fails, see [Troubleshooting](#troubleshooting) below.
|
||||
|
||||
## Step 8: Save Configuration
|
||||
|
||||
Click **Save** to store the DNS provider configuration. Credentials are encrypted at rest using AES-256-GCM.
|
||||
|
||||
## Step 9: Use with Wildcard Certificates
|
||||
|
||||
When creating a proxy host with a wildcard domain:
|
||||
|
||||
1. Navigate to **Proxy Hosts** → **Add Proxy Host**
|
||||
2. Enter a wildcard domain: `*.example.com`
|
||||
3. Select **Google Cloud DNS** from the DNS Provider dropdown
|
||||
4. Configure remaining settings
|
||||
5. Save
|
||||
|
||||
Charon will automatically obtain a wildcard certificate using DNS-01 challenge.
|
||||
|
||||
## Example Configuration
|
||||
|
||||
```yaml
|
||||
Provider Type: googleclouddns
|
||||
Name: GCP Cloud DNS - example.com
|
||||
Project ID: my-project-123456
|
||||
Service Account JSON: {"type":"service_account",...}
|
||||
Propagation Timeout: 120 seconds
|
||||
Polling Interval: 10 seconds
|
||||
Default: Yes
|
||||
```
|
||||
|
||||
## Required Permissions
|
||||
|
||||
The service account needs the following Cloud DNS permissions:
|
||||
|
||||
| Permission | Purpose |
|
||||
|------------|---------|
|
||||
| `dns.changes.create` | Create DNS record changes |
|
||||
| `dns.changes.get` | Check status of DNS changes |
|
||||
| `dns.managedZones.list` | List available DNS zones |
|
||||
| `dns.resourceRecordSets.create` | Create TXT records for ACME challenges |
|
||||
| `dns.resourceRecordSets.delete` | Clean up TXT records after validation |
|
||||
| `dns.resourceRecordSets.list` | List existing DNS records |
|
||||
| `dns.resourceRecordSets.update` | Update DNS records if needed |
|
||||
|
||||
> **Note:** The **DNS Administrator** role includes all these permissions. For fine-grained control, create a custom role.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Connection Test Fails
|
||||
|
||||
**Error:** `Invalid service account JSON`
|
||||
|
||||
- Verify the entire JSON content was pasted correctly
|
||||
- Ensure no extra whitespace or line breaks were added
|
||||
- Check the JSON is valid (use a JSON validator)
|
||||
- Re-download the key file and try again
|
||||
|
||||
**Error:** `Project not found` or `Project mismatch`
|
||||
|
||||
- Verify the Project ID matches the project in the service account JSON
|
||||
- Check the `project_id` field in the JSON matches your input
|
||||
- Ensure the project exists and is active
|
||||
|
||||
**Error:** `Permission denied` or `Forbidden`
|
||||
|
||||
- Verify the service account has the DNS Administrator role
|
||||
- Check the role is assigned at the project level
|
||||
- Ensure Cloud DNS API is enabled
|
||||
- Wait a few minutes after role assignment (propagation delay)
|
||||
|
||||
**Error:** `API not enabled`
|
||||
|
||||
- Navigate to APIs & Services → Library
|
||||
- Search for and enable Cloud DNS API
|
||||
- Wait 2-3 minutes for activation
|
||||
|
||||
### Certificate Issuance Fails
|
||||
|
||||
**Error:** `DNS propagation timeout`
|
||||
|
||||
- Cloud DNS typically propagates in 30-60 seconds
|
||||
- Increase Propagation Timeout to 180 seconds
|
||||
- Verify nameservers are correctly configured with your registrar
|
||||
- Check Google Cloud Status page for service issues
|
||||
|
||||
**Error:** `Zone not found`
|
||||
|
||||
- Ensure the DNS zone exists in Cloud DNS
|
||||
- Verify the domain matches the zone's DNS name
|
||||
- Check the service account has access to the zone
|
||||
|
||||
**Error:** `Record creation failed`
|
||||
|
||||
- Check for existing `_acme-challenge` TXT records that may conflict
|
||||
- Verify service account permissions
|
||||
- Review Charon logs for detailed API errors
|
||||
|
||||
### Nameserver Propagation
|
||||
|
||||
**Issue:** DNS changes not visible globally
|
||||
|
||||
- Nameserver changes can take 24-48 hours to propagate globally
|
||||
- Use [DNS Checker](https://dnschecker.org/) to verify propagation
|
||||
- Verify your registrar shows Google Cloud DNS nameservers
|
||||
- Wait for full propagation before attempting certificate issuance
|
||||
|
||||
### Rate Limiting
|
||||
|
||||
Google Cloud DNS API quotas:
|
||||
|
||||
- 10,000 queries per day (default)
|
||||
- 1,000 changes per day (default)
|
||||
- Certificate challenges typically use <20 requests
|
||||
|
||||
If you hit limits:
|
||||
|
||||
- Request quota increase via Google Cloud Console
|
||||
- Reduce frequency of certificate renewals
|
||||
- Contact Google Cloud support for production workloads
|
||||
|
||||
## Security Recommendations
|
||||
|
||||
1. **Dedicated Service Account:** Create a separate service account for Charon
|
||||
2. **Least Privilege:** Use a custom role with only required permissions
|
||||
3. **Key Rotation:** Rotate service account keys every 90 days
|
||||
4. **Key Security:** Store JSON key in a secrets manager, never in version control
|
||||
5. **Audit Logging:** Enable Cloud Audit Logs for DNS API calls
|
||||
6. **VPC Service Controls:** Consider using VPC Service Controls for additional security
|
||||
7. **Disable Unused Keys:** Delete old keys immediately after rotation
|
||||
|
||||
## Service Account Key Rotation
|
||||
|
||||
To rotate the service account key:
|
||||
|
||||
1. Create a new key following Step 4
|
||||
2. Update the configuration in Charon with the new JSON
|
||||
3. Test the connection to verify the new key works
|
||||
4. Delete the old key from the GCP console
|
||||
|
||||
```bash
|
||||
# Using gcloud CLI (optional)
|
||||
# List existing keys
|
||||
gcloud iam service-accounts keys list \
|
||||
--iam-account=charon-dns-challenge@PROJECT_ID.iam.gserviceaccount.com
|
||||
|
||||
# Create new key
|
||||
gcloud iam service-accounts keys create new-key.json \
|
||||
--iam-account=charon-dns-challenge@PROJECT_ID.iam.gserviceaccount.com
|
||||
|
||||
# Delete old key (after updating Charon)
|
||||
gcloud iam service-accounts keys delete KEY_ID \
|
||||
--iam-account=charon-dns-challenge@PROJECT_ID.iam.gserviceaccount.com
|
||||
```
|
||||
|
||||
## gcloud CLI Verification (Optional)
|
||||
|
||||
Test credentials before adding to Charon:
|
||||
|
||||
```bash
|
||||
# Activate service account
|
||||
gcloud auth activate-service-account \
|
||||
--key-file=/path/to/service-account-key.json
|
||||
|
||||
# Set project
|
||||
gcloud config set project YOUR_PROJECT_ID
|
||||
|
||||
# List DNS zones
|
||||
gcloud dns managed-zones list
|
||||
|
||||
# Test record creation (creates and deletes a test TXT record)
|
||||
gcloud dns record-sets create test-acme-challenge.example.com. \
|
||||
--zone=your-zone-name \
|
||||
--type=TXT \
|
||||
--ttl=60 \
|
||||
--rrdatas='"test-value"'
|
||||
|
||||
# Clean up test record
|
||||
gcloud dns record-sets delete test-acme-challenge.example.com. \
|
||||
--zone=your-zone-name \
|
||||
--type=TXT
|
||||
```
|
||||
|
||||
## Additional Resources
|
||||
|
||||
- [Google Cloud DNS Documentation](https://cloud.google.com/dns/docs)
|
||||
- [Service Account Documentation](https://cloud.google.com/iam/docs/service-accounts)
|
||||
- [Cloud DNS API Reference](https://cloud.google.com/dns/docs/reference/v1)
|
||||
- [Caddy Google Cloud DNS Module](https://caddyserver.com/docs/modules/dns.providers.googleclouddns)
|
||||
- [Google Cloud Status Page](https://status.cloud.google.com/)
|
||||
- [IAM Roles for Cloud DNS](https://cloud.google.com/dns/docs/access-control)
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [DNS Providers Overview](../dns-providers.md)
|
||||
- [Wildcard Certificates Guide](../certificates.md#wildcard-certificates)
|
||||
- [DNS Challenges Troubleshooting](../../troubleshooting/dns-challenges.md)
|
||||
|
||||
````
|
||||
@@ -1,37 +1,142 @@
|
||||
|
||||
# SSRF Remediation Plan (Index)
|
||||
# Charon Feature & Remediation Tracker
|
||||
|
||||
This file is intentionally SSRF-focused only.
|
||||
**Last Updated:** January 3, 2026
|
||||
|
||||
This document serves as the central index for all active plans, implementation specs, and outstanding work items.
|
||||
|
||||
---
|
||||
|
||||
## 1. SSRF Remediation
|
||||
|
||||
**Status:** 🔴 IN PROGRESS
|
||||
|
||||
The authoritative, Supervisor-updated SSRF plan is:
|
||||
|
||||
- [docs/plans/ssrf-remediation.md](docs/plans/ssrf-remediation.md)
|
||||
- [docs/plans/ssrf-remediation.md](ssrf-remediation.md)
|
||||
|
||||
## Merge policy (Supervisor requirement)
|
||||
### Merge Policy (Supervisor requirement)
|
||||
|
||||
- The global CodeQL exclusion for `go/request-forgery` in
|
||||
[.github/codeql/codeql-config.yml](.github/codeql/codeql-config.yml) must be removed
|
||||
[.github/codeql/codeql-config.yml](../../.github/codeql/codeql-config.yml) must be removed
|
||||
in the same PR/merge as the underlying SSRF fixes.
|
||||
- Phase 0 can include local-only recon (e.g., temporary local edit of CodeQL config to
|
||||
surface findings), but must not be a mergeable intermediate state.
|
||||
|
||||
## SSRF call sites (current known)
|
||||
### SSRF Call Sites (Current Known)
|
||||
|
||||
- Uptime monitor HTTP checks: `(*UptimeService).checkMonitor` in
|
||||
[backend/internal/services/uptime_service.go](backend/internal/services/uptime_service.go)
|
||||
- CrowdSec LAPI: `(*CrowdsecHandler).GetLAPIDecisions` and
|
||||
`(*CrowdsecHandler).CheckLAPIHealth` in
|
||||
[backend/internal/api/handlers/crowdsec_handler.go](backend/internal/api/handlers/crowdsec_handler.go)
|
||||
- Caddy Admin API: `caddy.NewClient` and `(*Client).Load/GetConfig/Ping` in
|
||||
[backend/internal/caddy/client.go](backend/internal/caddy/client.go)
|
||||
- URL connectivity test (SSRF-sensitive client): `utils.TestURLConnectivity` in
|
||||
[backend/internal/utils/url_testing.go](backend/internal/utils/url_testing.go)
|
||||
| Location | Function | File |
|
||||
|----------|----------|------|
|
||||
| Uptime Monitor | `(*UptimeService).checkMonitor` | [uptime_service.go](../../backend/internal/services/uptime_service.go) |
|
||||
| CrowdSec LAPI | `GetLAPIDecisions`, `CheckLAPIHealth` | [crowdsec_handler.go](../../backend/internal/api/handlers/crowdsec_handler.go) |
|
||||
| Caddy Admin API | `NewClient`, `Load/GetConfig/Ping` | [client.go](../../backend/internal/caddy/client.go) |
|
||||
| URL Connectivity Test | `utils.TestURLConnectivity` | [url_testing.go](../../backend/internal/utils/url_testing.go) |
|
||||
|
||||
## Relocated content (no deletions)
|
||||
---
|
||||
|
||||
- Patch coverage (Codecov) plan (previous Appendix A):
|
||||
[docs/plans/patch-coverage-codecov.md](docs/plans/patch-coverage-codecov.md)
|
||||
- CodeQL/Trivy local scan hygiene notes (generated artifacts, skip dirs, etc.):
|
||||
[docs/plans/codeql-local-hygiene.md](docs/plans/codeql-local-hygiene.md)
|
||||
- DNS provider feature spec (implementation-level):
|
||||
[docs/implementation/dns_providers_IMPLEMENTATION.md](docs/implementation/dns_providers_IMPLEMENTATION.md)
|
||||
## 2. DNS Provider Feature (Issue #21)
|
||||
|
||||
### Core Implementation
|
||||
|
||||
**Status:** ✅ COMPLETE
|
||||
|
||||
- **Implementation Spec:** [dns_providers_IMPLEMENTATION.md](../implementation/dns_providers_IMPLEMENTATION.md)
|
||||
- **Pull Request:** [#461](https://github.com/Wikid82/Charon/pull/461)
|
||||
|
||||
All core components implemented:
|
||||
|
||||
| Layer | Component | Status |
|
||||
|-------|-----------|--------|
|
||||
| Backend | Encryption Service (`crypto/encryption.go`) | ✅ Complete |
|
||||
| Backend | DNSProvider Model | ✅ Complete |
|
||||
| Backend | DNS Provider Service | ✅ Complete |
|
||||
| Backend | DNS Provider Handler | ✅ Complete |
|
||||
| Backend | Routes Registered | ✅ Complete |
|
||||
| Backend | Caddy DNS-01 Integration | ✅ Complete |
|
||||
| Frontend | API Client & Hooks | ✅ Complete |
|
||||
| Frontend | DNS Providers Page & Form | ✅ Complete |
|
||||
| Frontend | ProxyHost Integration | ✅ Complete |
|
||||
| Frontend | Translations | ✅ Complete |
|
||||
|
||||
### Acceptance Criteria Verification
|
||||
|
||||
| Criterion | Status |
|
||||
|-----------|--------|
|
||||
| Users can add, edit, delete, and test DNS provider configurations | ✅ Implemented |
|
||||
| Credentials encrypted at rest using AES-256-GCM | ✅ Implemented |
|
||||
| Credentials never exposed in API responses | ✅ Implemented (`json:"-"`) |
|
||||
| Proxy hosts with wildcard domains can select a DNS provider | ✅ Implemented |
|
||||
| Caddy successfully obtains wildcard certificates via DNS-01 | ✅ Implemented |
|
||||
| Backend unit test coverage ≥ 85% | ✅ **85.2%** (verified 2026-01-03) |
|
||||
| Frontend unit test coverage ≥ 85% | ✅ **87.8%** (verified 2026-01-03) |
|
||||
| User documentation completed | ✅ Complete (5 provider guides) |
|
||||
| All translations added | ✅ Complete |
|
||||
|
||||
### Verification Results (2026-01-03)
|
||||
|
||||
| Check | Result |
|
||||
|-------|--------|
|
||||
| Backend Coverage | ✅ 85.2% (threshold: 85%) |
|
||||
| Frontend Coverage | ✅ 87.8% (threshold: 85%) |
|
||||
| Security Scan (Trivy) | ✅ 0 Critical, 0 High |
|
||||
| Security Scan (govulncheck) | ✅ 0 vulnerabilities |
|
||||
| Pre-commit Hooks | ✅ All 11 hooks passed |
|
||||
| CHANGELOG | ✅ Entry exists in [Unreleased] |
|
||||
|
||||
### Outstanding Items (Pre-Merge)
|
||||
|
||||
- [x] ~~Run backend coverage report~~ — **85.2%** ✅
|
||||
- [x] ~~Run frontend coverage report~~ — **87.8%** ✅
|
||||
- [x] ~~Complete Google Cloud DNS setup guide~~ — Created ✅
|
||||
- [x] ~~Complete Azure DNS setup guide~~ — Created ✅
|
||||
- [ ] Manual E2E validation: DNS provider → wildcard proxy → certificate issued
|
||||
- [x] ~~CHANGELOG entry for DNS provider feature~~ — Already present ✅
|
||||
- [x] ~~Security scans (Trivy, govulncheck)~~ — Passed ✅
|
||||
|
||||
### Future Enhancements
|
||||
|
||||
**Status:** 📋 PLANNING
|
||||
|
||||
- **Planning Doc:** [dns_challenge_future_features.md](dns_challenge_future_features.md)
|
||||
|
||||
| Priority | Feature | Est. Time | Status |
|
||||
|----------|---------|-----------|--------|
|
||||
| **P0** | Audit Logging for Credential Operations | 8-12 hrs | ❌ Not Started |
|
||||
| **P1** | Key Rotation Automation | 16-20 hrs | ❌ Not Started |
|
||||
| **P1** | Multi-Credential per Provider (Zone-Specific) | 12-16 hrs | ❌ Not Started |
|
||||
| **P2** | DNS Provider Auto-Detection | 6-8 hrs | ❌ Not Started |
|
||||
| **P3** | Custom DNS Provider Plugins | 20-24 hrs | ❌ Not Started |
|
||||
|
||||
**Recommended Implementation Order:**
|
||||
1. Audit Logging (Security/Compliance baseline for SOC 2, GDPR, HIPAA)
|
||||
2. Key Rotation (Security hardening, annual rotation support)
|
||||
3. Multi-Credential (Enterprise/MSP multi-tenancy)
|
||||
4. Auto-Detection (UX improvement)
|
||||
5. Custom Plugins (Extensibility for power users)
|
||||
|
||||
---
|
||||
|
||||
## 3. Related Documents (Index)
|
||||
|
||||
| Document | Description |
|
||||
|----------|-------------|
|
||||
| [patch-coverage-codecov.md](patch-coverage-codecov.md) | Codecov patch coverage plan |
|
||||
| [codeql-local-hygiene.md](codeql-local-hygiene.md) | CodeQL/Trivy local scan hygiene notes |
|
||||
| [dns_providers_IMPLEMENTATION.md](../implementation/dns_providers_IMPLEMENTATION.md) | DNS provider full implementation spec |
|
||||
| [dns_challenge_future_features.md](dns_challenge_future_features.md) | DNS challenge future enhancements plan |
|
||||
|
||||
---
|
||||
|
||||
## 4. Definition of Done (All Features)
|
||||
|
||||
Before any feature is considered complete:
|
||||
|
||||
- [ ] Backend unit test coverage ≥ 85%
|
||||
- [ ] Frontend unit test coverage ≥ 85%
|
||||
- [ ] TypeScript check passes (`npm run type-check`)
|
||||
- [ ] Pre-commit hooks pass (`pre-commit run --all-files`)
|
||||
- [ ] CodeQL scans: zero Critical/High issues
|
||||
- [ ] Trivy scans: zero Critical/High vulnerabilities
|
||||
- [ ] All linters pass
|
||||
- [ ] Documentation updated
|
||||
- [ ] CHANGELOG updated
|
||||
|
||||
Reference in New Issue
Block a user