[install] powerdns 설치하기

By | 2016/05/27

Private DNS? POWERDNS!

DB를 마스터/슬레이브로 운영하고 있을 경우, 마스터 디비가 죽으면 슬레이브 디비를 마스터로 승격시켜주는 녀석들이 있다.(MMM, MHA등등) 그런데, 보통 디비를 바라보고 있는 클라이언트는 보통 아이피나 도메인을 통해서 디비를 바라보고 있을 것이다. 그런 상황에서 슬레이브가 마스터로 승격되어 봤자 클라이언트들은 죽어있는 마스터를 바라보게 마련이다.

이런경우 슬레이브를 마스터로 승격 시켜주는 것과 별개로 아이피나 도메인도 같이 바꿔줘야 하는데,
아이피를 바꾸려면 가상아이피라는 녀석을 써야한다. 그런데 지금 사용하는 클라우드 서비스에서는 가상아이피를 지원하지 않는관계로,어쩔 수 없이(?!) 도메인을 써야하는 상황이었다.

어쨌든 클라이언트들이 모르게 도메인만 슬쩍 바꿔버리면, 클라이언트는 마스터가 죽었는지 살았는지 모를테니, dns서버라는 녀석을 도입하기로 했다. 그중에 제일 간편해 보이는 녀석이 powerdns 였는데..(설치는 간편하지 않다) web api도 지원하고 해서 실제 서비스에 도입해서 사용하고 있다.

Private DNS라고 쓰긴했지만, 내가 그렇게 쓴다는거지, Public DNS 서버로 못쓴다는 얘기는 아니다.

궁금한 사람은 powerdns 문서 페이지와 github에서 더 많은 정보를 볼 수 있을 것이다.

MariaDB설치

PowerDNS는 벡엔드로 Mysql을 사용할 수 있는데, 나는 MariaDB를 사용하기로 했다. (이유가 있었던것 같은데, 까먹었다.)
여튼 설치를 해보자. root 유저로 들어가서 실행해야한다.

# apt-get update && apt-get upgrade -y
# apt-get install software-properties-common
# apt-key adv --recv-keys --keyserver hkp://keyserver.ubuntu.com:80 0xcbcb082a1bb943db
# add-apt-repository 'deb http://ftp.kaist.ac.kr/mariadb/repo/5.5/ubuntu trusty main'
# apt-get -y install libaio1 libdbd-mysql-perl libdbi-perl libmariadbclient18 libmysqlclient18 libnet-daemon-perl libplrpc-perl mariadb-client-5.5 mariadb-client-core-5.5 mariadb-common mysql-common mariadb-server mariadb-server-5.5 mariadb-server-core-5.5

mariadb 보안 적용

보안을 위해서 하는 건데, 테스트환경이라면 굳이 하지 않아도 된다.

$ mysql_secure_installation

위의 코드를 실행하면 아래와 같이 물어보는데, 읽어보고 yes를 해주면 된다.

Change the root password? [Y/n] n
Remove anonymous users? [Y/n] y
Disallow root login remotely? [Y/n] y
Remove test database and access to it? [Y/n] y
Reload privilege tables now? [Y/n] y
Thanks for using MariaDB!

powerdns 유저 생성및 데이터베이스와 테이블 생성

powerdns_init.sql이라는 파일을 하나 생성하고 아래의 내용을 채워넣자. (패스워드는 알아서 잘 바꿔주자. 복붙금지!)

CREATE DATABASE powerdns;
GRANT ALL ON powerdns.* TO 'pdns'@'localhost' IDENTIFIED BY 'password';
FLUSH PRIVILEGES;
USE powerdns;
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);

디비생성후에 다음의 커맨드로 mariadb에 반영해주자.

$ mysql -u root -p < powerdns_init.sql

Powerdns설치 (4.0.X)

/etc/apt/source.list에 아래한줄을 추가한다.

# add-apt-repository 'deb [arch=amd64] http://repo.powerdns.com/ubuntu trusty-auth-40 main'

그리고 /etc/apt/preferences.d/pdns 파일을 생성하고 아래 내용을 추가한다.

# touch /etc/apt/preferences.d/pdns
# echo -e "Package: pdns-*\nPin: origin repo.powerdns.com\nPin-Priority: 600" | sudo tee /etc/apt/preferences.d/pdns

위의 것들을 하면 아래의 명령어로 실행할 수 있다.

# curl https://repo.powerdns.com/FD380FBB-pub.asc | sudo apt-key add -
# apt-get update && apt-get upgrade
# apt-get install -y pdns-server pdns-backend-mysql
# rm /etc/powerdns/pdns.d/* ### 기존의 설정 삭제 꼭 해줘야한다.

설치시에 아래와 같은 에러가 난다면, 아래의 명령을 실행해주자.
# apt-get -f purge -y mysql-client

You might want to run 'apt-get -f install' to correct these.
The following packages have unmet dependencies:
 mariadb-server : Depends: mariadb-server-5.5 (= 5.5.49+maria-1~trusty) but 5.5.49-1ubuntu0.14.04.1 is installed
E: Unmet dependencies. Try using -f.

설치시 아래와 같은 화면이 나오는데, No를 선택해주자.

그리고 /etc/powerdns/pdns.d/pdns.local.gmysql.conf 파일을 아래와같이 수정해 주어야 한다.
디비의 유저와 패스워드를 잘 바꿔서 넣어주자.

### MySQL Configuration file
launch=gmysql
gmysql-host=localhost
gmysql-dbname=디비명
gmysql-user=유저명
gmysql-password=<pdns의 mysql 패스워드>

###수정후 mariadb를 재시작해준다. 
$ service pdns restart

pdns가 잘동작하는지 테스트

netstat와 dig를 사용했을 때 아래와 비슷하게 나와야 한다.

$ netstat -nlp |grep pdns
tcp        0      0 0.0.0.0:53              0.0.0.0:*               LISTEN      6793/pdns_server-in
udp        0      0 0.0.0.0:53              0.0.0.0:*                           6793/pdns_server-in
unix  2      [ ACC ]     STREAM     LISTENING     46518    6789/pdns_server    /var/run/pdns.controlsocket
$ dig @localhost
; <<>> DiG 9.9.5-3ubuntu0.8-Ubuntu <<>> @localhost
; (3 servers found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 28331
;; flags: qr rd; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 2800
;; QUESTION SECTION:
;.              IN  NS
;; Query time: 2 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Thu Mar 10 20:06:16 KST 2016
;; MSG SIZE  rcvd: 29

Poweradmin 설치

powerdns에는 Poweradmin 이라는 php관리 페이지가 따로 있다. 설치가 어렵지않고, 설치하면 많은 기능을 웹기반으로 쉽게사용할 수 있으니 설치하도록 하자. (커맨드라인으로 굳이하겠다면 말리지는 않음)

$ apt-get install -y unzip apache2 gettext libapache2-mod-php5 php5 php5-common php5-curl php5-dev php5-gd php-pear php5-imap  php5-ming php5-mysql php5-xmlrpc php5-mhash php5-mcrypt
$ pear upgrade pear/PEAR
$ pear install DB
$ pear install pear/MDB2#mysql

### php 모듈 활성화
$ php5enmod mcrypt
$ service apache2 restart

$ cd tmp
$ wget https://github.com/poweradmin/poweradmin/archive/master.zip -O poweradmin.zip
$ unzip poweradmin.zip
$ mv poweradmin-master /var/www/html/poweradmin

Poweradmin 설정

설치가 끝났으니 아래의 주소로 들어가서 설정을 하도록하자.

http://#{server_ip}/poweradmin/install/

들어가면 위와 같은 언어 선택 화면이 나온다. 대부분 영어겠지만, 익숙한 언어를 선택하고 Go to step2로 가자. 나는 영어를 선택했다.

스텝2는 별거 없다. 바로 Go to step3 를 누르자.

Step3에서는 DB와 Poweradmin에 대한 설정을 하게 된다.
적절한 값을 넣도록 하자.

Username : DB와 연결할 유저명을 적으면 된다. 우리는 위에서 pdns라는 유저를 생성했다. 
Password : 디비패스워드
Database type : MySQL
Hostname : localhost
DB Port : 3306
Database : powerdns
Poweradmin administrator password : 파워애드민에서 사용할 관리자 패스워드  

Username : poweradmin의 관리자명
Password: poweradmin의 관리자 패스워드
hostmaster.unixmen.local – SOA레코드를 만들때 없을경우 기본값으로 들어가는 값. 다음과 같은 방식이 된다. “hostmaster.example.net”.
ns1.unixmen.local – 템플릿을 만들때 주 네임서버로 설정되는 값. 요런식으로 적는다. “ns1.example.net”.
ns2.unixmen.local – 템플릿을 만들때 주 네임서버로 설정되는 값. 요런식으로 적는다. “ns2.example.net”.

잘 적은뒤에 Step5로 가자.

Step5에서는 poweradmin에서 powerdns의 유저가 디비에 접근할때의 권한을 SELECT, INSERT, UPDATE, DELETE 만주라고 권장하고 있다. 화면에 있는 내용을 mysql에서 실행해주면 된다.

Step6에서는 poweradmin의 설정파일을 “../inc/config.inc.php” 경로에 만들어라고 말을하고 있다. 해당 내용을 복사해서 만들어주자.
설정파일에 db_user가 admin 이라고 되어있는데, 디비에 유저가 생성되지 않은 경우가 있으므로 그경우에는 기존의 ‘pdns’유저로 해당 파일의 설정을 변경해주자.
나 같은 경우는 “/var/www/html/poweradmin/inc/config.inc.php” 경로에 생성을 했다. 7단계로 가자. 이게 설치는 거의 다되어 간다!

7단계에서는 DDNS를 사용하고 싶으면 mod_rewrite를 활성화 하라고 하고 있다.
그리고 반드시 “install” 디렉토리를 삭제하라고 한다.
다음으로 poweradmin의 “install” 디렉토리를 반.드.시. 삭제해야한다. (나는 사실 이름만 바꿨다. 실서버에서는 이렇게 하면 안된다.)

http://server_ip/poweradmin 으로 들어왔을 때 위와 같은 화면이 나오면 설치는 성공이다.
Username과 Password에 위에서 설정한 값을 넣으면 Poweradmin에 접근이 가능하다.
이제 설치는 끝이다.

DNS서버 설정

Add Master Zone을 추가하자.

Zone name에 ‘pkpk.com’ 등과 같은 사용하고 싶은 주도메인을 입력하고 Add zone 을 눌러서 추가해준다.

List zones에 들어가면 위와같은 화면이 나오고 빨간 동그라미친 곳에 들어가면 A record등을 추가할 수 있다.

alpha.pkpk.com 이라는 도메인을 요청하면 192.168.0.8로 응답을 주도록 세팅을 했다.

DNS서버 테스트

이제 잘되는지 테스트를 해보자. 먼저는 powerdns가 설치된 서버에서 실행을 해보자.
다음과 같은 코드를 실행해보자

$ dig alpha.pkpk.com A @127.0.0.1

아래와 비슷한 결과가 나오면 성공이다.

; <<>> DiG 9.9.5-3ubuntu0.8-Ubuntu <<>> alpha.pkpk.com A @127.0.0.1
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 18817
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 2800
;; QUESTION SECTION:
;alpha.pkpk.com.            IN  A
;; ANSWER SECTION:
alpha.pkpk.com.     5   IN  A   192.168.0.8
;; Query time: 0 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Thu Mar 10 21:21:09 KST 2016
;; MSG SIZE  rcvd: 59

이제 다른 서버에 DNS서버를 연결해서 테스트해보자.

### ubuntu14.04에서 실행했다. root권한으로 실행해야한다.
$ echo "nameserver dnsserver의 아이피"  >> /etc/resolvconf/resolv.conf.d/head
$ service networking restart
$ sudo resolvconf -u

설정이 끝났으니 위에서 추가한 alpha.pkpk.com 으로 핑을 날려보자.

$ ping alpha.pkpk.com
PING alpha.pkpk.com (192.168.0.8) 56(84) bytes of data.
64 bytes from 192.168.0.8: icmp_seq=1 ttl=64 time=0.398 ms
64 bytes from 192.168.0.8: icmp_seq=2 ttl=64 time=0.279 ms
64 bytes from 192.168.0.8: icmp_seq=3 ttl=64 time=0.282 ms
64 bytes from 192.168.0.8: icmp_seq=4 ttl=64 time=0.303 ms

--- alpha.pkpk.com ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3001ms
rtt min/avg/max/mdev = 0.279/0.315/0.398/0.051 ms

위와 같이 핑테스트가 잘되면 성공이다.

API

powerdns의 3.4버전부터 api를 사용가능하다.
우분투에서 apt-get install로 설치하는 녀석들은 버전이 낮은 경우가 많으니 주의하자.
설정파일에 아래와 같은 부분을 설정하고, powerdns를 재시작 해주면 활성화가 된다.

설정을 업데이트하는 API를 사용하려면, mysql의 설정의 binlog_format을 row로 변경해주어야 한다.
api=yes
api-key=changeme
webserver=yes

API 사용예제

<주의> API를 사용해서 만든 zone 정보만 API를 사용해서 조작할 수 있다. 이점에 유의해야한다.

# zone list
$ curl -H 'X-API-Key: changeme' http://192.168.0.44:8081/api/v1/servers/localhost/zones | jq .

# create zone
$ curl -X POST --data '{"name":"example.org.", "kind": "Native", "masters": [], "nameservers": ["ns1.example.org.", "ns2.example.org."]}' -v -H 'X-API-Key: changeme' http://192.168.0.44:8081/api/v1/servers/localhost/zones | jq .

# show zone info
$ curl -H 'X-API-Key: changeme' http://192.168.0.44:8081/api/v1/servers/localhost/zones/pkpk.com | jq .

# change sub domain info
$curl -X PATCH --data '{"rrsets": [ {"name": "gamedb1.pkpk.com", "type": "A", "ttl": 0, "changetype": "REPLACE", "records": [ {"content": "192.168.0.29", "disabled": false } ] } ] }' -H 'X-API-Key: changeme' http://192.168.0.44:8081/api/v1/servers/localhost/zones/pkpk.com | jq .