Monday, February 5, 2018

BASH based PowerDNS curl API call script to add A record and PTR records to PowerDNS


Note: This example assumes that the forward and reverse zones are already set as in the PowerDNS server.


The PowerDNS accepts the API PATCH calls with the JSON API.



The way it has been done in the example below using the JSON data templates for A and PTR records additions may not be optimal and it is very much possible that there are many ways of doing the same in a more proficient manner.


The JSON template file for adding the A record is named as "curlfileArecord.json" and looks like 


[root@powerdns ~]# cat addArecord.template.json
{"rrsets": [
  {"name": "fqdn.",
   "type": "A",
   "ttl": 86400,
   "changetype": "REPLACE",
   "set-ptr": true,
   "records": [ {"content": "ip", "disabled": false} ]
  }
 ]
}


The JSON template file for adding the PTR record is names as "curlfilePTRrecord.json" and looks like


[root@powerdns ~]# cat addPTRrecord.template.json
{
"rrsets": [
  {"name": "reversedIP.in-addr.arpa.",
   "type": "PTR",
   "ttl": 86400,
   "changetype": "REPLACE",
   "records": [ {"content": "fqdn.", "disabled": false} ]
  }
 ]
}



The Actual BASH Wrapper script is the below. 




[root@powerdns ~]# cat powerdnsAddRecords.sh
#!/bin/bash

# This script adds the A record as well as the PTR record to the DNS
# Takes 3 arguments exactly
# Positional arguments:
# Argument1: IP address of the record to be added to the DNS
# Argument2: Short name of FQDNm if FQDN is server1.example.com, the Argument will be the short name of the argument like server1
# Argument3: This is the name of the of domain in the format example.com if the server FQDN is server1.example.com


# Exit with 1 if the Argument passed is not equal to 3
echo "$#"
if [ "$#" != 3 ]; then
echo "$0: Usage : $(basename $0) <server ip address> <server short name> <domain name>"
exit 1;
fi


ip=$1
serverShortName=$2
domain=$3
fqdn=${serverShortName}.${domain}

# See the FQDN formation
echo $fqdn

# format the IP last 2 octets to have the reverse zone name
reversedForZone=$(echo $ip |awk -F "." '{print $2"." $1}')

# Reverse all the octets so as to have the PTR record to be added to the reverse zone
reversedIP=$(echo $ip| awk -F "." '{print $4 "." $3 "." $2 "." $1 }')

# Calculation of the reverse Zone
reverseZone="${reversedForZone}.in-addr.arpa"

# Calculation of the reverse zone URL for PowerDNS API call
reverseZoneApi="http://172.16.192.236:8081/api/v1/servers/localhost/zones/${reverseZone}."

echo $reverseZoneApi

# Calculation of the forward zone PowerDNS API
domainname=$domain
forwardZoneApi="http://172.16.192.236:8081/api/v1/servers/localhost/zones/${domainname}."
echo $forwardZoneApi

# Use the JSON template for A record so as to generate a file to be used to pass as data to CURL API call
cat addArecord.template.json | sed -e 's|fqdn|'"$fqdn"'|g' -e 's|ip|'"$ip"'|g' > curlfileArecord.json

# Use the JSON template for PTR record so as to generate the file to be used to pass as data to CURL API Call
cat addPTRrecord.template.json | sed -e 's|reversedIP|'"$reversedIP"'|g' -e 's|fqdn|'"$fqdn"'|g' > curlfilePTRrecord.json

# Add the A Record
curl -X PATCH -H 'X-API-Key: securekeyhere' $forwardZoneApi --data @curlfileArecord.json

# Add the PTR Record
curl -X PATCH -H 'X-API-Key: securekeyhere' $reverseZoneApi --data @curlfilePTRrecord.json

[root@powerdns ~]#



Sample run of the script is as 


[root@powerdns ~]# bash -x powerdnsAddRecords.sh 172.16.150.189 server1 example.com
+ echo 3
3
+ '[' 3 '!=' 3 ']'
+ ip=172.16.150.189
+ serverShortName=server1
+ domain=example.com
+ fqdn=server1.example.com
+ echo server1.example.com
server1.example.com
++ awk -F . '{print $2"." $1}'
++ echo 172.16.150.189
+ reversedForZone=16.172
++ echo 172.16.150.189
++ awk -F . '{print $4 "." $3 "." $2 "." $1 }'
+ reversedIP=189.150.16.172
+ reverseZone=16.172.in-addr.arpa
+ reverseZoneApi=http://172.16.192.236:8081/api/v1/servers/localhost/zones/16.172.in-addr.arpa.
+ echo http://172.16.192.236:8081/api/v1/servers/localhost/zones/16.172.in-addr.arpa.
http://172.16.192.236:8081/api/v1/servers/localhost/zones/16.172.in-addr.arpa.
+ domainname=example.com
+ forwardZoneApi=http://172.16.192.236:8081/api/v1/servers/localhost/zones/example.com.
+ echo http://172.16.192.236:8081/api/v1/servers/localhost/zones/example.com.
http://172.16.192.236:8081/api/v1/servers/localhost/zones/example.com.
+ cat addArecord.template.json
+ sed -e 's|fqdn|server1.example.com|g' -e 's|ip|172.16.150.189|g'
+ sed -e 's|reversedIP|189.150.16.172|g' -e 's|fqdn|server1.example.com|g'
+ cat addPTRrecord.template.json
+ curl -X PATCH -H 'X-API-Key: securekeyhere' http://172.16.192.236:8081/api/v1/servers/localhost/zones/example.com. --data @curlfileArecord.json
+ curl -X PATCH -H 'X-API-Key: securekeyhere' http://172.16.192.236:8081/api/v1/servers/localhost/zones/16.172.in-addr.arpa. --data @curlfilePTRrecord.json
[root@powerdns ~]#


If the script is run without any arguments


[root@powerdns ~]# bash powerdnsAddRecords.sh
0
powerdnsAddRecords.sh: Usage : powerdnsAddRecords.sh <server ip address> <server short name> <domain name>
[root@powerdns ~]#

Thursday, February 1, 2018

PowerDNS installation on CentOS7 and enabling the API


PowerDNS installation on CentOS7 and enabling the API 

Important reference:

https://github.com/poweradmin/poweradmin/blob/master/sql/poweradmin-mysql-db-structure.sql


Please Note: 

All "XXXXXXXXX" here are for password, these have to be replaced by actual password(s) you would like.



Ensure the EPEL repo is installed
--

On the OS for simplicity disable NetworkManager and the firewalld services and set the selinux to disabled mode.

yum -y install epel-release

--

Install the REPO for POWERDNS 4

--

Else create a repo file in /etc/yum.repos.d as the contents as below

echo '[powerdns-auth-40]
name=PowerDNS repository for PowerDNS Authoritative Server - version 4.0.X
baseurl=http://repo.powerdns.com/centos/$basearch/$releasever/auth-40
gpgkey=https://repo.powerdns.com/FD380FBB-pub.asc
gpgcheck=1
enabled=1
priority=90
includepkg=pdns*' > /etc/yum.repos.d/powerdns-auth.repo

echo '[powerdns-auth-40-debuginfo]
name=PowerDNS repository for PowerDNS Authoritative Server - version 4.0.X debug symbols
baseurl=http://repo.powerdns.com/centos/$basearch/$releasever/auth-40/debug
gpgkey=https://repo.powerdns.com/FD380FBB-pub.asc
gpgcheck=1
enabled=0
priority=90
includepkg=pdns*' > /etc/yum.repos.d/powerdns-auth-debuginfo.repo

--

install deltarpm and priority

yum -y install yum-plugin-priorities /usr/bin/applydeltarpm


--
Install these associated tools also

yum -y install php php-mcrypt php-pdo php-mysql pdns pdns-backend-mysql httpd httpd php php-devel php-gd php-imap php-ldap php-mysql php-odbc php-pear php-xml php-xmlrpc php-mbstring php-mcrypt php-mhash gettext

Install the PowerDNS 


yum -y install pdns

--

add the entries to the powerdns configuration file at the start
/etc/pdns/pdns.conf



echo 'setuid=pdns
setgid=pdns
launch=gmysql
gmysql-host=localhost
gmysql-user=powerdns
gmysql-password=XXXXXXXXX
gmysql-dbname=powerdns' > /etc/pdns/pdns.conf



--

install mariadb


yum -y install mariadb mariadb-server
--

Harden the MYSQL installation, even localhost only access to the MySQL DB would do here as the PDNS application is running on the same host as the MYSQL server


mysql_secure_installation

set the proper mysql values and set the mysql root user password

systemctl enable pdns httpd mariadb
systemctl start pdns httpd mariadb

--

login to mysql using the root passwd

mysql -u root -p


--

Refer to the website for the Database structure needed to be created
--

https://github.com/poweradmin/poweradmin/blob/master/sql/poweradmin-mysql-db-structure.sql
--


create database powerdns;

GRANT ALL ON powerdns.* TO 'powerdns'@'localhost' IDENTIFIED BY 'XXXXXXXXX';
GRANT ALL ON powerdns.* TO 'powerdns'@'powerdns.localdomain' IDENTIFIED BY 'XXXXXXXXX';
GRANT ALL ON powerdns.* TO 'powerdns'@'%' IDENTIFIED BY 'XXXXXXXXX';

flush privileges;

use powerdns;


CREATE TABLE users (
  id          INTEGER      NOT NULL AUTO_INCREMENT,
  username    VARCHAR(64)  NOT NULL,
  `password`  VARCHAR(128) NOT NULL,
  fullname    VARCHAR(255) NOT NULL,
  email       VARCHAR(255) NOT NULL,
  description TEXT         NOT NULL,
  perm_templ  TINYINT      NOT NULL,
  active      TINYINT      NOT NULL,
  use_ldap    TINYINT      NOT NULL,
  PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

START TRANSACTION;
    INSERT INTO users ( id, username, `password`, fullname, email
                      , description, perm_templ, active, use_ldap )
    VALUES ( 1, 'admin', '21232f297a57a5a743894a0e4a801fc3', 'Administrator'
           , 'admin@example.net', 'Administrator with full rights.', 1, 1, 0 );
COMMIT;

CREATE TABLE perm_items (
  id INTEGER       NOT NULL AUTO_INCREMENT,
  name VARCHAR(64) NOT NULL,
  descr TEXT       NOT NULL,
  PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

START TRANSACTION;
    INSERT INTO perm_items ( id, name, descr ) VALUES ( 41, 'zone_master_add', 'User is allowed to add new master zones.' );
    INSERT INTO perm_items ( id, name, descr ) VALUES ( 42, 'zone_slave_add', 'User is allowed to add new slave zones.' );
    INSERT INTO perm_items ( id, name, descr ) VALUES ( 43, 'zone_content_view_own', 'User is allowed to see the content and meta data of zones he owns.' );
    INSERT INTO perm_items ( id, name, descr ) VALUES ( 44, 'zone_content_edit_own', 'User is allowed to edit the content of zones he owns.' );
    INSERT INTO perm_items ( id, name, descr ) VALUES ( 45, 'zone_meta_edit_own', 'User is allowed to edit the meta data of zones he owns.' );
    INSERT INTO perm_items ( id, name, descr ) VALUES ( 46, 'zone_content_view_others', 'User is allowed to see the content and meta data of zones he does not own.' );
    INSERT INTO perm_items ( id, name, descr ) VALUES ( 47, 'zone_content_edit_others', 'User is allowed to edit the content of zones he does not own.' );
    INSERT INTO perm_items ( id, name, descr ) VALUES ( 48, 'zone_meta_edit_others', 'User is allowed to edit the meta data of zones he does not own.' );
    INSERT INTO perm_items ( id, name, descr ) VALUES ( 49, 'search', 'User is allowed to perform searches.' );
    INSERT INTO perm_items ( id, name, descr ) VALUES ( 50, 'supermaster_view', 'User is allowed to view supermasters.' );
    INSERT INTO perm_items ( id, name, descr ) VALUES ( 51, 'supermaster_add', 'User is allowed to add new supermasters.' );
    INSERT INTO perm_items ( id, name, descr ) VALUES ( 52, 'supermaster_edit', 'User is allowed to edit supermasters.' );
    INSERT INTO perm_items ( id, name, descr ) VALUES ( 53, 'user_is_ueberuser', 'User has full access. God-like. Redeemer.' );
    INSERT INTO perm_items ( id, name, descr ) VALUES ( 54, 'user_view_others', 'User is allowed to see other users and their details.' );
    INSERT INTO perm_items ( id, name, descr ) VALUES ( 55, 'user_add_new', 'User is allowed to add new users.' );
    INSERT INTO perm_items ( id, name, descr ) VALUES ( 56, 'user_edit_own', 'User is allowed to edit their own details.' );
    INSERT INTO perm_items ( id, name, descr ) VALUES ( 57, 'user_edit_others', 'User is allowed to edit other users.' );
    INSERT INTO perm_items ( id, name, descr ) VALUES ( 58, 'user_passwd_edit_others', 'User is allowed to edit the password of other users.' );
    INSERT INTO perm_items ( id, name, descr ) VALUES ( 59, 'user_edit_templ_perm', 'User is allowed to change the permission template that is assigned to a user.' );
    INSERT INTO perm_items ( id, name, descr ) VALUES ( 60, 'templ_perm_add', 'User is allowed to add new permission templates.' );
    INSERT INTO perm_items ( id, name, descr ) VALUES ( 61, 'templ_perm_edit', 'User is allowed to edit existing permission templates.' );
COMMIT;

CREATE TABLE perm_templ (
  id    INTEGER      NOT NULL AUTO_INCREMENT,
  name  VARCHAR(128) NOT NULL,
  descr TEXT         NOT NULL,
  PRIMARY KEY  (id)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

START TRANSACTION;
    INSERT INTO perm_templ ( id, name, descr )
    VALUES ( 1, 'Administrator', 'Administrator template with full rights.' );
COMMIT;

CREATE TABLE perm_templ_items (
  id INTEGER       NOT NULL AUTO_INCREMENT,
  templ_id INTEGER NOT NULL,
  perm_id INTEGER  NOT NULL,
  PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

START TRANSACTION;
    INSERT INTO perm_templ_items ( id, templ_id, perm_id )
    VALUES ( 1, 1, 53 );
COMMIT;

CREATE TABLE zones (
  id            INTEGER NOT NULL AUTO_INCREMENT,
  domain_id     INTEGER NOT NULL,
  owner         INTEGER NOT NULL,
  `comment`     TEXT,
  zone_templ_id INTEGER NOT NULL,
  PRIMARY KEY (id),
  KEY owner (owner)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

CREATE TABLE zone_templ (
  id    INTEGER      NOT NULL AUTO_INCREMENT,
  name  VARCHAR(128) NOT NULL,
  descr TEXT         NOT NULL,
  owner INTEGER      NOT NULL,
  PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

CREATE TABLE zone_templ_records (
  id            INTEGER      NOT NULL AUTO_INCREMENT,
  zone_templ_id INTEGER      NOT NULL,
  name          VARCHAR(255) NOT NULL,
  `type`        VARCHAR(6)   NOT NULL,
  content       VARCHAR(255) NOT NULL,
  ttl           INTEGER      NOT NULL,
  prio          INTEGER      NOT NULL,
  PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

CREATE TABLE records_zone_templ (
    domain_id INTEGER NOT NULL,
    record_id INTEGER NOT NULL,
    zone_templ_id INTEGER NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

CREATE TABLE migrations (
    version VARCHAR(255) NOT NULL,
    apply_time INTEGER NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

CREATE TABLE domains (
  id                    INT AUTO_INCREMENT,
  name                  VARCHAR(255) NOT NULL,
  master                VARCHAR(128) DEFAULT NULL,
  last_check            INT DEFAULT NULL,
  type                  VARCHAR(6) NOT NULL,
  notified_serial       INT DEFAULT NULL,
  account               VARCHAR(40) DEFAULT NULL,
  PRIMARY KEY (id)
) Engine=InnoDB;

CREATE UNIQUE INDEX name_index ON domains(name);


CREATE TABLE records (
  id                    INT AUTO_INCREMENT,
  domain_id             INT DEFAULT NULL,
  name                  VARCHAR(255) DEFAULT NULL,
  type                  VARCHAR(10) DEFAULT NULL,
  content               VARCHAR(64000) DEFAULT NULL,
  ttl                   INT DEFAULT NULL,
  prio                  INT DEFAULT NULL,
  change_date           INT DEFAULT NULL,
  disabled              TINYINT(1) DEFAULT 0,
  ordername             VARCHAR(255) BINARY DEFAULT NULL,
  auth                  TINYINT(1) DEFAULT 1,
  PRIMARY KEY (id)
) Engine=InnoDB;

CREATE INDEX nametype_index ON records(name,type);
CREATE INDEX domain_id ON records(domain_id);
CREATE INDEX recordorder ON records (domain_id, ordername);


CREATE TABLE supermasters (
  ip                    VARCHAR(64) NOT NULL,
  nameserver            VARCHAR(255) NOT NULL,
  account               VARCHAR(40) NOT NULL,
  PRIMARY KEY (ip, nameserver)
) Engine=InnoDB;


CREATE TABLE comments (
  id                    INT AUTO_INCREMENT,
  domain_id             INT NOT NULL,
  name                  VARCHAR(255) NOT NULL,
  type                  VARCHAR(10) NOT NULL,
  modified_at           INT NOT NULL,
  account               VARCHAR(40) NOT NULL,
  comment               VARCHAR(64000) NOT NULL,
  PRIMARY KEY (id)
) Engine=InnoDB;

CREATE INDEX comments_domain_id_idx ON comments (domain_id);
CREATE INDEX comments_name_type_idx ON comments (name, type);
CREATE INDEX comments_order_idx ON comments (domain_id, modified_at);


CREATE TABLE domainmetadata (
  id                    INT AUTO_INCREMENT,
  domain_id             INT NOT NULL,
  kind                  VARCHAR(32),
  content               TEXT,
  PRIMARY KEY (id)
) Engine=InnoDB;

CREATE INDEX domainmetadata_idx ON domainmetadata (domain_id, kind);


CREATE TABLE cryptokeys (
  id                    INT AUTO_INCREMENT,
  domain_id             INT NOT NULL,
  flags                 INT NOT NULL,
  active                BOOL,
  content               TEXT,
  PRIMARY KEY(id)
) Engine=InnoDB;

CREATE INDEX domainidindex ON cryptokeys(domain_id);


CREATE TABLE tsigkeys (
  id                    INT AUTO_INCREMENT,
  name                  VARCHAR(255),
  algorithm             VARCHAR(50),
  secret                VARCHAR(255),
  PRIMARY KEY (id)
) Engine=InnoDB;

CREATE UNIQUE INDEX namealgoindex ON tsigkeys(name, algorithm);
---

Start and Enable the HTTPD, MARIADB and the PDNS service on the Operating System 

systemctl start httpd
systemctl enable httpd

systemctl start mariadb
systemctl enable mariadb

systemctl start pdns
systemctl enable pdns

--

Installation and configuration of the poweradmin web server

cd /var/www/html

wget http://downloads.sourceforge.net/project/poweradmin/poweradmin-2.1.7.tgz
# or download and upload to the server this file at /var/www/html

tar zxvf poweradmin-2.1.7.tgz

cd poweradmin-2.1.7/inc

--

Open the following link in a Browser. Replace <IPAddress of the powerdns server> with the IP address of the PowerDNS Server 


http://<IPAddress of the powerdns server>/poweradmin-2.1.7/install/
--

follow online instructions

1) On the first screen have the Language selection
2) Click on 'Go to Step 3'
3) DB instance information. For the Database, give the information about username, password, Database type(MySQL), Hostname: can let this be localhost or the FQDN on the server (same server in this case as the PDNS server is running the DB locally), DB Port: on which MySQL is running, Database name, Poweradmin administrator password that you want ot set.
4) Configuration for poweradmin : username: admin, password: set the password, Hostmaster: FQDN of the server itself, Primary Name server, secondary name server, for these 2 give the values as FDQN itself for the server.
5) 
Run this command on the MySQl DB login 

6) Step 6
GRANT SELECT, INSERT, UPDATE, DELETE
ON powerdns.*
TO 'admin'@'localhost'
IDENTIFIED BY 'XXXXXXXXX';

7) 


If you want support for the URLs used by other dynamic DNS providers, run "cp install/htaccess.dist .htaccess" and enable mod_rewrite in Apache.

You should (must!) remove the directory "install/" from the Poweradmin root directory. You will not be able to use Poweradmin if it exists. Do it now.

After you have removed the directory, you can login to Poweradmin with username "admin" and password "XXXXXXXXX". You are highly encouraged to change these as soon as you are logged in.
---


Accessing the PowerDNS Application


Access the powerdns WebUI at 

http://<IP_address_of_POWERDNS_server>/poweradmin-2.7.1/

--

Enabling the Inbound APIs for PowerDNS



To Enable the powerDNS server API, ensure that these are there in the /etc/pdns/pdns.conf

api=yes
api-key=securekeyhere


--

Restart PowerDNS service 

systemctl restart pdns
---
Test the API using CURL 




curl -v -H 'X-API-Key: securekeyhere' http://172.16.192.236:8081/api/v1/servers/localhost | jq .


If the Output is like the below, you are good to go.
Test other things in the API also 

{
  "config_url": "/api/v1/servers/localhost/config{/config_setting}",
  "daemon_type": "authoritative",
  "id": "localhost",
  "type": "Server",
  "url": "/api/v1/servers/localhost",
  "version": "4.0.5",
  "zones_url": "/api/v1/servers/localhost/zones{/zone}"
}