This is a drop-in provider for apnscp to enable DNS support using PowerDNS. This module may use PostgreSQL or MySQL as a backend driver.
PostgreSQL can be used by specifying powerdns_driver=pgsql, cpcmd config:set will accomplish this:
cpcmd config:set apnscp.bootstrapper powerdns_enabled true
cpcmd config:set apnscp.bootstrapper powerdns_driver pgsql
upcp -sb software/powerdns
# Optionally set all accounts to use PowerDNS
cpcmd config:set dns.default-provider powerdnsPowerDNS is now setup to accept requests on port 8081. Requests require an authorization key that can be found in /etc/pdns/pdns.conf
# Install jq if not already installed
yum install -y jq
# This is your API key
grep '^api-key=' /etc/pdns/pdns.conf | cut -d= -f2
curl -v -H 'X-API-Key: APIKEYABOVE' http://127.0.0.1:8081/api/v1/servers/localhost | jq .
apnscp provides a DNS-only license class that allows apnscp to run on a server without the capability to host sites. These licenses are free and may be requested via my.apnscp.com. Contact license@apnscp.com if these licenses are not available at time of writing for manual issuance.
Alternatively, apnscp can be configured to connect to a remote PowerDNS server. This is useful if running a DNS cluster and want every apnscp server to connect to it.
cpcmd config:set apnscp.bootstrapper powerdns_enabled true
cpcmd config:set apnscp.bootstrapper powerdns_apionly true
upcp -sb software/powerdns
cpcmd config:set dns.default-provider powerdnsProced with the setup in section "apnscp DNS provider setup" below. The API key will be sourced from your remote server.
PowerDNS may be configured via files in /etc/pdns/local.d. In addition to this location, Bootstrapper supports injecting settings via powerdns_custom_config. For example,
cpcmd config:set apnscp.bootstrapper 'powerdns_custom_config' '["allow-axfr-ips":1.2.3.4,"also-notify":1.2.3.4]'
cd /usr/local/apnscp/resources/playbooks
ansible-playbook addin.yml --extra-vars=addin=apnscp-powerdnsallow-axfr-ips and also-notify directives will be set whenever the addin plays are run.
ALIAS is a synthetic record that allows CNAME records to be set on the zone apex. ALIAS records require powerdns_enable_recursion to be enabled as well as an optional powerdns_recursive_ns to be set otherwise it will default to the system in /etc/resolv.conf.
cpcmd config:set apnscp.bootstrapper powerdns_enable_recursion true
cpcmd config:set apnscp.bootstrapper powerdns_recursive_ns '[1.1.1.1,1.0.0.1]'
# Then re-run the addin...
cd /usr/local/apnscp/resources/playbooks
ansible-playbook addin.yml --extra-vars=addin=apnscp-powerdnsIn the above example, only local requests may submit DNS modifications to the server. None of the below examples affect querying; DNS queries occur over 53/UDP typically (or 53/TCP if packet size exceeds UDP limits). Depending upon infrastructure, there are a few options to securely accept record submission, all of which require an API key for submission.
Apache's ProxyPass directive send requests to the backend. Brute-force attempts are protected by mod_evasive bundled with apnscp. Requests over this medium are protected by SSL, without HTTP/2 to ameliorate handshake overhead. In all but the very high volume API request environments, this will be acceptable.
In this situation, the endpoint is https://myserver.apnscp.com/dns. Changes are made to /etc/httpd/conf/httpd-custom.conf within the <VirtualHost ... :443> bracket (with SSLEngine On!). After adding the below changes, systemctl restart httpd.
<Location /dns>
ProxyPass http://127.0.0.1:8081
ProxyPassReverse http://127.0.0.1:8081
</Location>
Downsides: minor SSL overhead. Dependent upon Apache. Upsides: easy to setup. Protected by threat deterrence. PowerDNS accessible remotely via an easily controlled URI.
In the above example, API requests can be made via https://myserver.apnscp.com/dns, e.g.
curl -q -H 'X-API-Key: SOMEKEY' https://myserver.apnscp.com/dns/api/v1/servers/localhostAs hinted above, placing PowerDNS behind Apache confers brute-force protection by mod_evasive. By default, 10 of the same requests in 2 seconds can trigger a brute-force block. Two solutions exist, either raise the same-page request threshold or disable mod_evasive.
Working off the example above <Location /dns> ...
<Location /dns>
# Raise threshold to 30 same-page requests in 2 seconds
DOSPageCount 30
DOSPageInterval 2
# Or disable entirely
DOSEnabled off
</Location>
PowerDNS can also run by itself on a different port. In this situation, the network is configured to block all external requests to port 8081 except those whitelisted. For example, if the entire 32.12.1.1-32.12.1.255 network can be trusted and under your control, then whitelist the IP range:
cpcmd rampart:whitelist 32.12.1.1/24Additionally, PowerDNS' whitelist must be updated as well. This can be quickly accomplished using the apnscp.bootstrapper Scope:
cpcmd config:set apnscp.bootstrapper powerdns_localonly false
cd /usr/local/apnscp/resources/playbooks
ansible-playbook addin.yml --extra-vars=addin=apnscp-powerdns
Downsides: requires whitelisting IP addresses for access to API server. Must run on port different than Apache. Upsides: operates independently from Apache.
The server may be accessed once the source IP has been whitelisted,
curl -q -H 'X-API-Key: SOMEKEY' http://myserver.apnscp.com/api/v1/servers/localhostEvery server that runs apnscp may delegate DNS authority to PowerDNS. This is ideal in distributed infrastructures in which coordination allows for seamless server-to-server migrations.
Taking the API key from above and using the SSL + Apache approach above, let's configure /usr/local/apnscp/config/auth.yaml. Configuration within this file is secret and is not exposed via apnscp's API. Once set restart apnscp to compile configuration, systemctl restart apnscp.
pdns:
# This url may be different if using running PowerDNS in standalone
uri: https://myserver.apnscp.com/dns/api/v1
key: your_api_key_here
type: native
ns:
- ns1.yourdomain.com
- ns2.yourdomain.com
recursion: false
## Optional additional nameserversurivalue is the hostname of your master PowerDNS server running the HTTP API webserver (without a trailing slash)keyvalue is the API Key inpdns.confon the master nameserver.typevalue defines domain type for replication. It's usually set tonativewhen using DB replication, and tomasterwhen using master-slave pdns replication (in such cluster the slaves should set this value toslave, while superslaves will do it automatically when creating ingested zones).nsvalue is a list of nameservers as in the example above. Put nameservers on their own lines prefixed with a hyphen and indented accordingly. There is not currently a limit for the number of nameservers you may use, 2-5 is typical and should be geographically distributed per RFC 2182.recursioncontrols ALIAS records, which are CNAMEs on apex (RFC 1034). Enabling requires configuration ofresolverandexpand-aliasin pdns.conf.
PowerDNS may be configured as the default provider for all sites using the dns.default-provider Scope. When adding a site in Nexus or AddDomain the key will be replaced with "DEFAULT". This is substituted automatically on account creation.
cpcmd config:set dns.default-provider powerdnsDo not set dns.default-provider-key. API key is configured via
config/auth.yaml.
- Module- overrides Dns_Module behavior
- Validator- service validator, checks input with AddDomain/EditDomain helpers
All module methods can be overwritten. The following are the bare minimum that are overwritten for this DNS provider to work:
atomicUpdate()attempts a record modification, which must retain the original record if it failszoneAxfr()returns all DNS recordsadd_record()add a DNS recordremove_record()removes a DNS recordget_hosting_nameservers()returns nameservers for the DNS provideradd_zone_backend()creates DNS zoneremove_zone_backend()removes a DNS zone
See also: Creating a provider (hq.apnscp.com)
Submit a PR and have fun!