Skip to content

ajgargan/bind9

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

43 Commits
 
 

Repository files navigation

BIND9 CentOS 7 named-chroot with SELinux and Local Firewalld enabled

What is this:

UserData script for Centos 7 Chroot Bind DNS Server

  • SELinux enabled
  • BIND Running in chroot
  • Firewalld running on instance
  • Single forward only zone example

NB!!! THIS IS WORK IN PROGRESS AND BY NO MEANS EXHAUSTIVE

Using this:

  • Launch dcos-centos7-201710261514(ami-0075d079) in eu-west region . (This was chosen because of dcos(Data Center OS))
  • Launch into a Public Subnet
  • Enable UDP and TCP 53(DNS) in the Security group and TCP 22(SSH)
  • Configure host with an SSH Keypair you have access to.
  • Paste the UserData below into the instance UserData under "Advanced" (Substitute your own MYDOMAIN and MYSSHPORT)

Single Host UserData script

#!/bin/sh -x
# -x so we can see whats going on from the console output and logs

# Set your VARS here
MYDOMAIN=dnsdemo.osite.co.za
MYSSHPORT=22

# Ensure SELinux is off so we can install and configure things
# We will enable it when we are done
setenforce 0

# Update all packages
yum update -y

# Set my hostname
hostnamectl set-hostname ns1.${MYDOMAIN}

# install the chrooted bind package
yum install -y bind-chroot firewalld 

# turn off the non chroot named
systemsctl stop named
systemctl disable named

# turn off and disable docker
systemsctl stop docker
systemctl disable docker

# turn off and disable postfix
systemctl stop postfix
systemctl disable postfix

# create zone files and config
cat <<EOF >/etc/named.conf
options {
    listen-on port 53 { any; };
    directory       "/var/named";
    dump-file       "/var/named/data/cache_dump.db";
    statistics-file "/var/named/data/named_stats.txt";
    memstatistics-file "/var/named/data/named_mem_stats.txt";
    allow-query     { any; };
    recursion no;

    dnssec-enable yes;
    dnssec-validation yes;

    /* Path to ISC DLV key */
    bindkeys-file "/etc/named.iscdlv.key";

    managed-keys-directory "/var/named/dynamic";

    pid-file "/run/named/named.pid";
    session-keyfile "/run/named/session.key";
};
logging {
        channel default_debug {
                file "data/named.run";
                severity dynamic;
        };
};

zone "." IN {
        type hint;
        file "named.ca";
};

zone "${MYDOMAIN}" {
    type master;
    file "${MYDOMAIN}.signed";
    allow-update{none;};
};

include "/etc/named.rfc1912.zones";
include "/etc/named.root.key";
EOF

cat <<EOF >/var/named/${MYDOMAIN}
\$ORIGIN dnsdemo.osite.co.za.
\$TTL 60
@   IN  SOA ns1.${MYDOMAIN}.    root.${MYDOMAIN}. (
                2017051004 ; se = serial number
                60         ; ref = refresh
                60         ; ret = update retry
                60         ; ex = expiry
                60 )       ; min = minimum

@           IN      NS      ns1.${MYDOMAIN}.
ns1         IN      A       192.168.0.33
wiki        IN      CNAME   wiki.osite.co.za.
EOF

chown root.named /var/named/${MYDOMAIN}
chmod 640 /var/named/${MYDOMAIN}

# Install package to make better entropy for cloud server entropy
yum install -y epel-release 
yum install haveged

cd /var/named/
# create DNSSEC signing keys
# Key Signing Key
dnssec-keygen -a NSEC3RSASHA1 -b 2048 -n ZONE ${MYDOMAIN}
# Zone Signing Key
dnssec-keygen -f KSK -a NSEC3RSASHA1 -b 4096 -n ZONE ${MYDOMAIN}

# Ensure private key perms
chown root:root /var/named/K${MYDOMAIN}.*private
chmod 600 /var/named/K${MYDOMAIN}.*private

# Find key file names to add to zone
KEY1=$(basename $(ls /var/named/K${MYDOMAIN}.*key | head -n1))
KEY2=$(basename $(ls /var/named/K${MYDOMAIN}.*key | tail -n1))

# Add keys to zone file
cat <<EOF >>/var/named/${MYDOMAIN}
\$INCLUDE $KEY1
\$INCLUDE $KEY2
EOF

# sign zone (creates /var/named/dnsdemo.osite.co.za.signed)
dnssec-signzone -A -3 $(head -c 1000 /dev/random | sha1sum | cut -b 1-16) -N INCREMENT -o ${MYDOMAIN} -t ${MYDOMAIN}

# Set SELinux Contexts (not reallly required see autorelabel near the end)
# semanage fcontext -a -t named_zone_t /etc/named.conf
# semanage fcontext -a -t named_zone_t /var/named/${MYDOMAIN}

# setup the named-chroot. The above configs will be merged into the chroot
/usr/lib/exec/setup-named-chroot.sh /var/named/chroot on

# turn on and persist the named-chroot service
systemctl enable named-chroot
systemctl start named-chroot

# So we can get the DS RECORDS for our Registrar
cat /var/named/dsset-${MYDOMAIN}.

# Set firewalling to allow DNS access
systemctl enable firewalld 
systemctl start firewalld
firewall-cmd --permanent --zone=public --add-service dns
firewall-cmd --reload

# Harden Kernel Options
cat <<EOF >/etc/sysctl.d/hardening.conf
#Disable the IP Forwarding
net.ipv4.ip_forward=0
#Disable the Send Packet Redirects
net.ipv4.conf.all.send_redirects=0
net.ipv4.conf.default.send_redirects=0
#Disable ICMP Redirect Acceptance
net.ipv4.conf.all.accept_redirects=0
net.ipv4.conf.default.accept_redirects=0
#Enable Bad Error Message Protection
net.ipv4.icmp_ignore_bogus_error_responses=1

#Restricting Core Dumps
fs.suid_dumpable=0
#Enable Exec Shield
kernel.exec-shield=1
#Enable randomized Virtual Memory Region Placement
kernel.randomize_va_space=2
EOF

# Harden limits around core dumps
cat <<EOF >/etc/limits.d/99_core_hardening.conf
*    hard   core    0
EOF

# backup sshd config
cp /etc/ssh/sshd_config /etc/ssh/sshd_config.orginal

# Function to be able to set SSHD params
function set_sshd_param() 
{ 
   grep -v $1 /etc/ssh/sshd_config > /etc/ssh/sshd_config.tmp
   echo "$1 $2" >> /etc/ssh/sshd_config.tmp 
   
   # Only change the actual config if we don't break it.
   /usr/sbin/sshd -t -f /etc/ssh/sshd_config.tmp
   if [ $? -eq 0 ]
   then
       mv /etc/ssh/sshd_config.tmp /etc/ssh/sshd_config
   fi
}

set_sshd_param Protocol 2
set_sshd_param PubkeyAuthentication yes
set_sshd_param PasswordAuthentication no
set_sshd_param PermitRootLogin no
set_sshd_param UsePAM yes
set_sshd_param Port $MYSSHPORT

# restart sshd the function above already tests for a broken config
# we will reboot and then sshd will come up with new config anyway
# systemctl sshd restart

# Ensure that SELinux is enabled
sed -i 's/permissive/enforcing/g' /etc/selinux/config

# Tell SELinux to correct the file contexts
touch /.autorelabel

# restart server so that sysctl/limits changes can be effected and SELinux can be turned on and relabel file contexts as required.
reboot

Testing

  • From an Internet connected host
    • dig @<your_public_ip> wiki.dnsdemo.osite.co.za +dnssec
    • dig @<your_public_ip> ns1.dnsdemo.osite.co.za +dnssec
    • dig dig DNSKEY dnsdemo.osite.co.za. @<your_public_ip> +multiline

Next Steps

Create CFN Template with

  • EC2 Instance ns0 as master which does not accept resolves
  • EC2 Instance ns1 as slave which resolves AZ1
  • EC2 Instance ns2 as slave which resolves AZ2
  • 1 EIP for each instance
  • UserData which injects the EIP's into the BIND configs
  • CFN-Hup for managing changes to the ZoneFile on ns0
  • EC2 Instance Bastion host
  • SG for Name Servers
    • Allow zone transfers and lookups to ns0/1/2
    • Allow SSH From Bastion SG
  • SG for Bastion
    • Allow SSH from CIDR provided

Add DNSSEC zone signing

DNSSEC is not currently supported by all TLD and Registrars, notably for co.za. This was added late 2017. Being ready for when it is is not a bad thing.

  • setup Key Signing Keys and Zone Signing Key
  • add both Keys to bottom of zonefile($INCLUDE )
  • sign zonefiles with Zone Signing Key
  • configure DS Records with registrar (osite.co.za) in this case. Which itself will need to be signed up to the TLD.
  • Test with:
    • dig +dnssec @8.8.8.8 some.domain.com eg:
      # dig +dnssec @8.8.8.8 www.cloudflare.com
    
      ; <<>> DiG 9.9.4-RedHat-9.9.4-61.el7 <<>> +dnssec @8.8.8.8 www.cloudflare.com
      ; (1 server found)
      ;; global options: +cmd
      ;; Got answer:
      ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 51511
      ;; flags: qr rd ra ad; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 1
    
      ;; OPT PSEUDOSECTION:
      ; EDNS: version: 0, flags: do; udp: 512
      ;; QUESTION SECTION:
      ;www.cloudflare.com.		IN	A
    
      ;; ANSWER SECTION:
      www.cloudflare.com.	4	IN	A	198.41.215.162
      www.cloudflare.com.	4	IN	A	198.41.214.162
      www.cloudflare.com.	4	IN	RRSIG	A 13 3 5 20180512071419 20180510051419 35273 cloudflare.com. oJ4UB0kPYK0ckwfRndLdT/1up9pb9kFIFDYPe5fPPffcK9h4NyAw1PBy EWzS3TqVUaSAJbdvJezLC5X0gz/3Ig==
    
      ;; Query time: 25 msec
      ;; SERVER: 8.8.8.8#53(8.8.8.8)
      ;; WHEN: Fri May 11 06:14:29 UTC 2018
      ;; MSG SIZE  rcvd: 189
    

UserData script

  • Use an isolated block device for the chroot

    • Set the following fsoptions
      • noexec – Do not set execution of any binaries on this partition (prevents execution of binaries but allows scripts).
      • nodev – Do not allow character or special devices on this partition (prevents use of device files such as zero, sda etc).
      • nosuid – Do not set SUID/SGID access on this partition (prevent the setuid bit).
  • Lock down root shell /bin/nologin && /etc/securetty

    • echo > /etc/securetty
    • usermod -s /sbin/login root
  • Possibly look at fail2ban etc. and also TCP Connection rate limiting via Firewalld/IPTABLES but realistically SSH shouldn't be accessible directly from outside the network. http://www.win.tue.nl/~vincenth/ssh_rate_limit_firewalld.htm

  • Enable Auditing

  • Enable remote syslogging

  • Enable host monitoring

References:

DNSSEC

SELinux

Host Hardening

About

UserData script for Centos 7 Chroot Bind DNS Server

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published