Arvutiteaduse instituut
  1. Kursused
  2. 2020/21 kevad
  3. Süsteemihaldus (LTAT.06.003)
EN
Logi sisse

Süsteemihaldus 2020/21 kevad

  • Home
  • Practicals
  • FAQ
  • References

0. Overview of Lab 3 :

Welcome to 3rd lab. Here the short action list we will do in this lab:

  1. Verifying previous lab tasks
  2. Installing updates
  3. Performing backup
  4. Installing Domain Name Server
  5. Configuring own local resolver server (allowing recursion and caching)
  6. Configuring own domain zone, understanding world and local resolvers

1.Make sure you did finish all the tasks of the previous week.

PS! Before continuing please make sure you have completed all previous labs.

  1. Access to ETAIS was granted and you can login with your UT credentials.
  2. VM was created and is visible in the list of VMs in ETAIS
  3. VM is reachable on External IP (from UT eduroam Wi-Fi or UT VPN)
  4. VM has SSH service running and you can login into VM using SSH private key
  5. VM has scoring account created, scoring can login using his SSH private key.
  6. Everything on scoring.sa.cs.ut.ee is green
  7. You have set a root password for your VM.

Additionally - Securing your ssh server

One thing that makes SSH server more secure is disabling password authentication. We disable it since we use our private key to log in and we disable password login, because people often use bad (easy to quess) passwords. We want to eliminate that risk and since we use key, we disable it.

  • Open and edit the file /etc/ssh/sshd_config
    • Change the value of PasswordAuthentication to no.
    • After modifying the configuration file, restart the sshd.service. Do not worry, this will not terminate the existing ssh connections.

2. Check for the updates using CentOS package manager

We have worked with package manager yum and/or dnf during Lab2. We upgraded packages.

  • Check if any updates are available
    • dnf check-update
  • Perform the upgrade if needed
    • dnf update or you can use dnf upgrade
  • Reboot the VM in case Linux Kernel or Initial RAM-fs was upgraded
    • This will be visible from the upgrade logs
    • Alternatively you can list the /boot directory to check if any files were updated recently
      • Consider the ls command, please have a look at options -l, -t, -r and -h (those might be helpful to produce detailed, time-ordered output)

We can count the system up-to-date if there is no more updates suggested by the package manager

  • In case you performed a reboot, make sure the VM booted and is back on-line and you can ssh into it.

After upgrading the system, it is wise to clean the left-overs: the downloaded rpm packages. Moreover it is wise to remove the packages that are not used anymore. The are two commands responsible for performing these actions:

# Uninstall the not used packages
yum autoremove -y
yum clean all

Perform the cleaning and remove not used packages

Extra reading material for package managers

DNF Command Reference
YUM cheat sheet

3. Perform backup

We are about to introduce some portion of changes to our system during this lab, therefore it is wise to backup the current state first. Pay attention that one of the changes we do is the firewall configurations, mistake in firewall configuration might result in locking the network access. Once network access is lost - you can't control your VM over SSH anymore. There is a recovery console (Action button in ETAIS next to your VM has Open console option), but that only works if you have set a root user password. The ETAIS infrastructure does allows to perform the snapshots of the hard-drives. By doing the snapshot you are saving the state of the whole hard drive. Once the snapshot is done you can proceed with dangerous actions knowing that you can always recover to last snapshot's state in case you misconfigure something.

In ETAIS interface issue the snapshot of the hard-drive

  • ETAIS -> Resources -> VMs -> Your VM Name -> VM snapshots -> Create

4. Firewall - Open UDP and TCP port 53 for the lab

Computers and especially servers usually utilize their own firewalls for security reasons. This allows the most privileged user of the machine to dictate how the network should from to/through/from the machine. The most usual case for this is opening ports for services, so they could be reached from the outside world.

Usually, to top it off, with any sensible cloud provider you have their own extra (second) layer of firewall, which has to be configured from outside the machine. This is to make sure, that even if your machine becomes compromised, network security policies (firewall rules) could not be changed easily.

From this lab onward we need UDP and TCP port 53 to be open for our VMs, so that we could build a working DNS solution. DNS usually uses port 53/udp for everything, but with big enough queries it switches over to 53/tcp. To do that for the cloud provider layer, follow these steps:

  • Go to ETAIS -> Resources -> VMs -> Your VM -> Manage security groups -> Create -> Name: DNS (Description: allowing UDP and TCP port 53 for DNS) -> Submit.
  • For the newly created DNS security group-> Actions -> Set rules -> Add rule -> Ethernet type: IPv4 -> Direction: Ingress -> IP protocol: UDP -> From port: 53 -> To port: 53 -> Remote CIDR: 0.0.0.0/0 -> Remote security group: None
    • Do the same for TCP.
  • Press Submit.

Now the security group has been created. We should add it to our machine also.

  • Go to ETAIS -> Resources -> VMs -> Actions -> Update Security groups -> Add the newly created Security Group DNS to the list of Security Groups -> Submit

When you open any other port, you also have to do it in ETAIS interface. This is not a one time thing.

Let's make sure the DNS service can also be accessed on the host level:

  • firewall-cmd --add-service=dns --permanent
  • firewall-cmd --add-port=8301/udp --permanent # This is a service that helps us find your machine in the network.
  • firewall-cmd --add-port=8301/tcp --permanent # Being able to connect to it is not important, but practice makes perfect.
  • firewall-cmd --reload

The output of previous commands should be success.

Both firewall-cmd commands should report on a new line: success

5. Disable IPv6

The ETAIS cloud does not suggest any IPv6 network providers, therefore is is pointless to keep the IPv6 stack up in our VMs. In this section we are going to disable the IPv6 stack by alternating kernel runtime parameters.

System wide configuration variables are managed using sysctl utility. Example:

  • To print the whole list of system settings use:
    • # sysctl -A
  • To see specific variable value:
    • # sysctl variableName
  • To set a specific variable to a new value use:
    • # sysctl <variable>=<value>

This will however change only running system setting and will reset to default values after system restart. In order to alter the default values put the corresponding variables in the end of /etc/sysctl.conf file, example content of /etc/sysctl.conf (only few last lines shown):

...

 # My default value of aa.bb.cc_var1 variable
 # NB! This is an example, do not use this!
 aa.bb.cc_var1=1

...

During this Lab we do not configure any service to rely on IPv6 hence we do not need the system wide IPv6 stack. Let's disable it using well studied sysctl utility.

Disable the use of IPv6:

  • Check the value of the following variables:
    • net.ipv6.conf.default.disable_ipv6
    • net.ipv6.conf.all.disable_ipv6
  • Change current system config using sysctl command, set the value of both variables to 1
  • To make the changes persistent after reboot(s) create the /etc/sysctl.d/70-ipv6.conf file, add the abovementioned variables. Save and close the file file.

Afterwards enter

  • sysctl --load /etc/sysctl.d/70-ipv6.conf

Now if you check your network interfaces using ip addr l command, there should be no inet6 prefixed lines.

  • $ ip addr l

And if you still see inet6 lines in the output, there is something you may have missed in the previous manual.

6. Domain Name System (DNS) using BIND software

DNS (Domain Name Service) is the main name service used in the Internet. Domain name services are used to translate names meaningful to humans into the numerical/binary addresses/numbers (and vice versa). Practically every system relies on a working domain name service. The domain name service does not have to be set up in-house, most often it is provided by the Internet Service Provider (ISP).

Extra materials

  • Wikipedia: Domain Name System

Domain Hierarchy for System Administration Labs

For our practicals we will use our own domain hierarchy starting from the top level domains. DNS management is based on strict delegation, so we are unable to introduce our "fake" top level domains into the "real" DNS system used in the Internet.

The domain hierarchy is divided into zones based on authority:

  • The authority over root domain and top level domains will belong to the teaching staff. We will be using top level domain .sa.cs.ut.ee.
  • Every participant/system will have authority over a second-level domain vm_name.sa.cs.ut.ee, under which one or more names may be defined. "vm_name" refers to the name to the machine you've set inside minu.etais.ee. It is mandatory to have a name for every host/sub system in the lab group under each of these second-level domains.
  • The general form for these names is <service>.vm_name.sa.cs.ut.ee Here "<service>" refers to any services we will be setting up in the future.

For example:

  • If student John Doe has his UT study number book B12345 and his VM was named B12345 then full hostname is B12345.sa.cs.ut.ee. You will have a different matrix number representing your VM name (host name), but the top-level domain .sa.cs.ut.ee will stay the same in your FQDN.

Changing hostname

By default all VM instances created in this course are given an hostname of <vm_name>.novalocal by ETAIS during the initial setup. During this lab we are going to setup a personal DNS server (serving personal domain <vm_name>.sa.cs.ut.ee). Therefore we have to prepare the VM by changing its host name from the ETAIS' default notation to full qualified domain notation, Example for B12345 in B12345.sa.cs.ut.ee domain:

* short notation: B12345
* fqdn notation: B12345.sa.cs.ut.ee

To check your current host name use the hostname command.

  • $ hostname

Which will return your VM's default hostname (set by ETAIS).

The host name is held in file /etc/hostname, by altering the single line in this file you will alter the name of your host. In addition there is a /etc/hosts file, which provides fixed host name to ip address mappings, and has the following content (only the line we are interested in is shown):

127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
... 

The line shown above allows to resolve host name localhost to a local IP address 127.0.0.1 (without any requests to external services like DNS). This especially useful when testing your services locally, if you consider the simple command, like:

  • $ ping localhost
$ ping localhost
PING localhost (127.0.0.1) 56(84) bytes of data.
64 bytes from localhost (127.0.0.1): icmp_seq=1 ttl=64 time=0.052 ms
64 bytes from localhost (127.0.0.1): icmp_seq=2 ttl=64 time=0.060 ms
...

We need to add another line in /etc/hosts associating your current hostname to 127.0.1.1, in case we change our domain we need to modify this line. Example:

  • my short host name is <vm_name>, and my new domain is .sa.cs.ut.ee, so the full domain name <vm_name>.sa.cs.ut.ee
  • the line to be added should look something like this:
    • 127.0.1.1 <vm_name> <vm_name>.sa.cs.ut.ee

Now change your host name as described above, using pattern <vm_name>.sa.cs.ut.ee for the new value. You can do it by editing files:

  • /etc/hostname
    • change the default hostname to your full hostname <vm_name>.sa.cs.ut.ee
      • <vm_name> - your current hostname in short notation ( a result of hostname command)
  • /etc/hosts
    • Add the line
      • 127.0.1.1 <vm_name>.sa.cs.ut.ee <vm_name>
  • To reiterate <vm_name> is a placeholder for student's matrix number. Students' matrix number will look something along the lines B12345
  • NOW reboot your instance to apply changes!
  • The logon screen must display the same hostname
  • When logged in, use the following command to display the hostname:
    • $ hostname --long
      • It should report you hostname in FQDN (<vm_name>.sa.cs.ut.ee)
  • Try to ping yourself using your new hostname

7. Configuring the BIND Name Server

First install the Bind 9 DNS server related packages.

Install packages:

  • bind
  • bind-utils

Now lets create a directory for logging and necessary files within that directory, that will be populated by the logging confiuration that will be added later in this lab.

  • Create directory log into /var/named.
  • Change the owner (user and group) of the directory to named.
  • Create file default into /var/named/log.
  • Change its owner (user and group) to named.
  • Create file auth_servers into /var/named/log.
  • Change its owner (user and group) to named.
  • Create file zone_transfers into /var/named/log.
  • Change its owner (user and group) to named.
  • Create file client_security into /var/named/log.
  • Change its owner (user and group) to named.
  • Create file queries into /var/named/log.
  • Change its owner (user and group) to named.
  • Create file query-errors into /var/named/log.
  • Change its owner (user and group) to named.

As the BIND name server runs with the rights of the root user and group named (not root), you should always make sure that the main configuration file and zone files have the correct permissions and group ownership. Every file to be read by the BIND DNS server must be readable by named group. If you get "permission denied" errors, use the following commands to set the owner or group ownership, example:

  • # chown root:named /etc/targetConfFile.conf

and following commands to set the correct permissions: (Learn More)

  • # chmod 640 /etc/targetConfFile.conf
    • Will set rights rw- r-- ---
  • # chmod g+r /etc/targetConfFile.conf
    • Will just set read right for the group
  • Use chown to change owner/group. Use ls -la to check permissions/owner/group.

The main configuration file for BIND is :

  • /etc/named.conf <-- Main configuration file - bind options, logging options, zones. This could be split into smaller segments if necessary, but means you would have to specify the include statement in the main configuration file.

Lets start configuring the DNS server by adding proper logging configuration. Replace the default logging options in the named.conf with the following:

logging {
     channel default_log {
          file "/var/named/log/default" versions 3 size 20m;
          print-time yes;
          print-category yes;
          print-severity yes;
          severity info;
     };
     channel auth_servers_log {
          file "/var/named/log/auth_servers" versions 100 size 20m;
          print-time yes;
          print-category yes;
          print-severity yes;
          severity info;
     };
     channel zone_transfers_log {
          file "/var/named/log/zone_transfers" versions 3 size 20m;
          print-time yes;
          print-category yes;
          print-severity yes;
          severity info;
     };
     channel client_security_log {
          file "/var/named/log/client_security" versions 3 size 20m;
          print-time yes;
          print-category yes;
          print-severity yes;
          severity info;
     };
//
// If you have the category ‘queries’ defined, and you don’t want query logging
// by default, make sure you add option ‘querylog no;’ - then you can toggle
// query logging on (and off again) using command ‘rndc querylog’
//
     channel queries_log {
          file "/var/named/log/queries" versions 600 size 20m;
          print-time yes;
          print-category yes;
          print-severity yes;
          severity info;
     };
//
// This channel is dynamic so that when the debug level is increased using
// rndc while the server is running, extra information will be logged about
// failing queries.  Other debug information for other categories will be
// sent to the channel default_debug (which is also dynamic), but without
// affecting the regular logging.
//
     channel query-errors_log {
          file "/var/named/log/query-errors" versions 5 size 20m;
          print-time yes;
          print-category yes;
          print-severity yes;
          severity dynamic;
     };
//
// This is the default syslog channel, defined here for clarity.  You don’t
// have to use it if you prefer to log to your own channels.
// It sends to syslog’s daemon facility, and sends only logged messages
// of priority info and higher.
// (The options to print time, category and severity are non-default.)
//
     channel default_syslog {
          print-time yes;
          print-category yes;
          print-severity yes;
          syslog daemon;
          severity info;
     };
//
// This is the default debug output channel, defined here for clarity.  You
// might want to redefine the output destination if it doesn’t fit with your
// local system administration plans for logging.  It is also a special
// channel that only produces output if the debug level is non-zero.
//
     channel default_debug {
          print-time yes;
          print-category yes;
          print-severity yes;
          file "named.run";
          severity dynamic;
     };
//
// Log routine stuff to syslog and default log:
//
     category default { default_syslog; default_debug; default_log; };
     category config { default_syslog; default_debug; default_log; };
     category dispatch { default_syslog; default_debug; default_log; };
     category network { default_syslog; default_debug; default_log; };
     category general { default_syslog; default_debug; default_log; };
//
// Log messages relating to what we got back from authoritative servers during
// recursion (if lame-servers and edns-disabled are obscuring other messages
// they can be sent to their own channel or to null).  Sometimes these log
// messages will be useful to research why some domains don’t resolve or
// don’t resolve reliably
//
     category resolver { auth_servers_log; default_debug; };
     category cname { auth_servers_log; default_debug; };
     category delegation-only { auth_servers_log; default_debug; };
//
// Log together all messages relating to authoritative zone propagation
//
     category notify { zone_transfers_log; default_debug; };
     category xfer-in { zone_transfers_log; default_debug; };
     category xfer-out { zone_transfers_log; default_debug; };
//
// Log together all messages relating to client access and security.
// (There is an additional category ‘unmatched’ that is by default sent to
// null but which can be added here if you want more than the one-line
// summary that is logged for failures to match a view).
//
     category client{ client_security_log; default_debug; };
     category security { client_security_log; default_debug; };
//
// If you have the category ‘queries’ defined, and you don’t want query logging
// by default, make sure you add option ‘querylog no;’ - then you can toggle
// query logging on (and off again) using command ‘rndc querylog’
//
     category queries { queries_log; };
//
// This logging category will only emit messages at debug levels of 1 or
// higher - it can be useful to troubleshoot problems where queries are
// resulting in a SERVFAIL response.
//
     category query-errors {query-errors_log; };
};

Now we add the simple caching DNS configuration to our bind server. This in order to get rid of the forwarding the DNS resolv queries to 10.10.10.1. Having the caching DNS server running locally on the same host will to the trick. Instead of forwarding the queries to 10.10.10.1 we will use our own resolver on 127.0.0.1 which has recursive resolving (and also caching) enabled.

Edit the DNS configuration file named.conf:

Now find the options { ... } declaration in options file and make sure the following lines are there:

listen-on port 53 { any; };
listen-on-v6 port 53 { none; };
...
allow-query     { any; };
...
recursion yes;
...
dnssec-enable no;
dnssec-validation no;

Do not change any lines that weren't mentioned.

Regarding the previous configuration, we first of all declare, that only anyone should be allowed to send resolve queries to our bind server, by having allow-query { any; }; defined as such. Secondly, we disable queries from IPv6, which we have disabled previously in section 5. In addition we increase the scope of IPv4 by putting bind listen on all interfaces' port 53 listen-on port 53 { any; }; Then we enable recursion, and finally turn off dnssec.

The recursion is needed in order to let bind act as standard caching recursive resolver (like those assigned by DHCP or put manually in /etc/resolv.conf).

  • Example query "where is courses.cs.ut.ee" is then resolved as follows:
    • "where is .ee"
    • "where is ut.ee"
    • "where is cs.ut.ee"
    • "where is courses.cs.ut.ee"
  • The often made queries are cached and answered explicitly

Now you can check your configuration using named-checkconf utility

  • # named-checkconf

No output means configuration is OK.

Start the name server (service named):

  • # systemctl start named (use systemctl stop named if you already started it before). If you prefer to use the service command you can start the service with # service named start and stopping the service with # service named stop.

Now query the service status and if needed, check the log files (those we have created in the beginning)

  • # service named status
  • # systemctl status named
  • # journalctl -xn

If everything works fine and no error is reported, you may check how your local resolver is performing:

  • $ dig @127.0.0.1 courses.cs.ut.ee
  • $ dig @127.0.0.1 www.google.com

If you have an error related to permissions to /var/named/log/default , please run the following command:

  • restorecon -Rv /var/named

This command relabels the security of that folder, allowing Bind to write there properly. Now systemctl start named should work properly.

It should answer with list of IP addresse for courses.cs.ut.ee like this:

; <<>> DiG 9.11.4-P2-RedHat-9.11.4-26.P2.el8 <<>> @127.0.0.1 courses.cs.ut.ee
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 53403
;; flags: qr rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 2, ADDITIONAL: 4

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
; COOKIE: 4d3b69aaf5aa48ca539139635e63c827c5801f3d6572b073 (good)
;; QUESTION SECTION:
;courses.cs.ut.ee.		IN	A

;; ANSWER SECTION:
courses.cs.ut.ee.	4320	IN	CNAME	web.cs.ut.ee.
web.cs.ut.ee.		4320	IN	A	193.40.36.57
web.cs.ut.ee.		4320	IN	A	193.40.36.55

;; AUTHORITY SECTION:
cs.ut.ee.		4320	IN	NS	ns2.ut.ee.
cs.ut.ee.		4320	IN	NS	ns.ut.ee.

;; ADDITIONAL SECTION:
ns2.ut.ee.		10800	IN	A	193.40.5.76
ns.ut.ee.		10800	IN	A	193.40.5.99
ns2.ut.ee.		10800	IN	AAAA	2001:bb8:2002:500::76

;; Query time: 23 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Sat Mar 07 18:13:27 EET 2020
;; MSG SIZE  rcvd: 218

If you get answer like this for courses.cs.ut.ee then local resolver is performing well. You may want to enable it for auto-starting at the boot time:

Enable auto-starting the named:

  • # systemctl enable named

The /etc/resolv.conf will not be rewritten by DHCP client (next time we reboot) and stays static. So we can safely edit it to rely on your own local resolver for doing DNS queries by replacing the namesever variable value with 127.0.0.1

Edit /etc/resolv.conf

  • Change nameserver option to 127.0.0.1
    • in case you have multiple - you should leave just one
  • Change search option to your personal domain <vm_name>.sa.cs.ut.ee

Reboot the VM. After rebooting make sure the /etc/resolv.conf is not modified (you should see your configuration there and nothing should be changed).

Now your local resolver is used system wide, so you can test it by just pinging some hosts by name:

  • $ ping www.google.com

Should resolve www.google.com and start pinging it.

Creating a Personal Domain for named

PS! Before continuing please make sure you have completed all of the previous steps.

This means your Virtual Machine is in System Administration course cluster and accessible over SSH and VPN connection.

  1. /etc/hostname file has your hostname in FQDN format <vm_name>.sa.cs.ut.ee
    • <vm_name> refers to the hostname of your VM that was chosen chosen during VM setup - your study book number.
  2. You can access your Virtual Machine over SSH with Putty or any other SSH client
  3. You can access your Virtual Machine with an SSH key over SSH
  4. Service bind is running and enabled systemctl status named.service -l
  5. Local DNS resolver is capable of resolving world addresses
    • dig @127.0.0.1 www.ut.ee
    • dig @127.0.0.1 www.google.com
  6. /etc/resolv.conf has a line nameserver 127.0.0.1
    • /etc/resolv.conf is not getting rewritten on reboots
  7. The OS can use the local DNS resolver to resolve any DNS host name
    • nslookup www.ut.ee
    • nslookup www.google.com

Adding zone definition to the local resolver

Creating a new zone is a two step process:

  • First, the records for the zone must be entered into the zone file
  • Second, the zone must be described/declared in the /etc/named.conf file.

Understanding the zone record files

The typical Zone file contains information about associations between host names and IP addresses within the domain of responsibility. The records inside the Zone file can be of different types:

  • SOA - Start of Authority. Defines the zone name, an e-mail contact and various time and refresh values applicable to the zone.
  • A - IPv4 Address record. An IPv4 address for a host.
  • AAAA - IPv6 Address record. An IPv6 address for a host. Current IETF recommendation for IPv6 forward-mapped zones.
  • NS - Name Server. Defines the authoritative name server(s) for the domain (defined by the SOA record) or the sub-domain.
  • MX - Mail Exchange. A preference value and the host name for a mail server/exchange that will service this zone. RFC 974 defines valid names.
  • PTR - IP address (IPv4 or IPv6) to host. Used in reverse maps.
  • CNAME - Canonical Name. An alias name for a host. Causes redirection for a single RR at the owner-name.

More details about record types can be found here.

Example Zone file content looks as follows:

NB! In Zone file ; denotes comments in configuration

;
; Zone file for domain-example.org
$ORIGIN domain-example.org.  ; Zone starting point in the name-space tree
                     ; (if skipped - the origin is inferred by the DNS server based on
                     ; zone declaration in name.conf.local file
$TTL 15M             ; Default expiration time for all resources
@ IN SOA ns.domain-example.org. root.domain-example.org.(
	 2012020101       ; Serial
		15M       ; Refresh (15 minutes)
		5M        ; Retry (5 minutes)
		604800    ; Expire (7 days in seconds)
		600 )     ; Negative Cache TTL
@       IN      NS      ns            ; name server for domain-example.org
@       IN      A       172.17.6.1    ; IPv4 address for domain-example.org
ns      IN      A       172.17.6.1    ; IPv4 address for ns.domain-example.org
@       IN      MX  10  mail          ; mail server for domain-example.org
myhost  IN      A       172.17.6.5    ; IPv4 address for myhost.domain-example.org
mail    IN      A       172.17.6.6    ; IPv4 address for mail.domain-example.org
myhost2 IN      A       172.17.6.7    ; IPv4 address for myhost2.domain-example.org
www     IN      CNAME   myhost        ; www is an alias for myhost in domain-example.org
ftp     IN      CNAME   myhost        ; ftp is an alias for myhost in domain-example.org
www.other-domain.org. IN A 192.168.1.11 ;  www.other-domain.org. is outside of domain-example.org
                                      ; and therefore needs to be declared using FQDN

The syntax explained here:

  • ; - Comment, disabled line
  • $ORIGIN - Zone starting point in the name-space tree, (if skipped - the origin is inferred by the DNS server based on zone declaration in name.conf.local file
  • $TTL - Default expiration time for all resources (cache time, specified in seconds)
    • (alternatively M, H might be appended to denote minutes or hours)
  • @ IN SOA ns.domain-example.org. root.domain-example.org.( 2012020101 15M 5M 604800 600) :
    • @ - Will be expanded to $ORIGIN if specified or assigned by DNS server
      • (in current example to domain-example.org)
    • IN - Protocol family:
      • IN - Internet protocol (IP)
      • HS and CH - historic MIT protocols from the times there was DNS but there was no IP
    • SOA - Zone authority info:
    • ns.domain-example.org - Address of name-server
    • root.domain-example.org - Will be expanded to root@domain-example.org and will correspond to email address of DNS master in the domain-example.org
    • 2012020101 - Serial Number (as specified here):
      • Unsigned 32 bit value in range 1 to 4294967295 with a maximum increment of 2147483647. In BIND implementations this is defined to be a 10 digit field. This value MUST increment when any resource record in the zone file is updated. A slave (Secondary) DNS server will read the master DNS SOA record periodically, either on expiry of refresh (defined below) or when it receives a NOTIFY and compares, arithmetically, its current value of sn with that received from the master. If the sn value from the master is arithmetically HIGHER than that currently stored by the slave then a zone transfer (AXFR/IXFR) is initiated by the slave. If the value of sn from the master DNS SOA is the same or LOWER then no zone transfer is initiated.
      • The convention is to use a date based sn value to simplify the task of incrementing the sn - the most popular convention being yyyymmddss where yyyy = year, mm = month and dd = day ss = a sequence number in case you update it more than once in the day!

As you can see after declaring SOA Zone authority, the actual Zone related data is added: the zone records:

  • <name> <ttl> <class> <type> <data>
    • name record name
    • ttl time to live in seconds, how long cache lives, if skipped $TTL variable is used.
    • class record class, the protocol family (in modern world only IN remains)
    • type record type
    • data type related value of the record

Record name can be one of three:

  • Short host name (inside current domain), like ns or mail , which will be then automatically extended to ns.domain-example.org and mail.domain-example.org .
  • FQDN (Fully-Qualified Domain Name), like www.otherd-domain.org.
    • In this case we have to terminate FQDN with . in order to avoid auto-expansion to www.otherd-domain.org.domain-example.org
  • @ sign which will be expanded to domain-example.org denoting the domain itself.

Create your zone file

You need to create the zone file in /etc/named/, but first let's make sure you know your domain:

Personal student domain is a sub-domain of sa.cs.ut.ee zone and has your VM's name as the domain name; therefore, if my VM's name is <vm_name> , then my domain would be <vm_name>.sa.cs.ut.ee - from this point onward the FQDN format of your domain shall be reffered to as <your_domain>.

Here we assume you got your domain name correctly and we proceed with Zone file creation:

Create the file:

  • <vm_name>.sa.cs.ut.ee in the /etc/named directory
    • here <vm_name> is your personal domain name
    • example: if my domain name is student-test.sa.cs.ut.ee then the file that needs to be created is called student-test.sa.cs.ut.ee
  • If you setup the named directory properly, it should be automatically assigned to named group, and if not, please make sure you did assigned the ownership and permissions properly to the named directory.

If the file was created properly you may edit the zone and add the bare minimal amount of zone records to your zone file.

Edit the zone file you have just created, add following:

  • Default time-to-live value of 15 minutes
  • SOA Authority record of your domain
    • having ns1.<your_domain>. as the name server
    • having root.<your_domain>. as the email of DNS master
    • having serial properly specified
    • having refresh interval of 15 minutes
    • having retry interval of 5 minutes
    • having expiry interval 2 hours
    • having negative cache TTL 600 seconds
  • NS record of your domain pointing to host ns1 in your domain
  • A records:
    • ns1 pointing to your External IP address
    • <your_domain> pointing to your External IP address
    • <your_hostname> pointing to your External IP address

Example file of ours /etc/named/student-test.sa.cs.ut.ee , domain student-test.sa.cs.ut.ee and IP 172.17.64.a :

;
; BIND data file for local zone student-test.sa.cs.ut.ee;
$TTL    15M
@       IN      SOA     ns1.student-test.sa.cs.ut.ee. root.student-test.sa.cs.ut.ee. (
                     2012020201         ; Serial
                            15M         ; Refresh
                             5M         ; Retry
                           120M         ; Expire
                            600 )       ; Negative Cache TTL
@              IN      NS      ns1
@              IN      A       172.17.64.a
ns1            IN      A       172.17.64.a
student-test   IN      A       172.17.64.a

If you did edit the file properly the following command may be used to test if the Zone file is valid

  • # named-checkzone <your_domain> /etc/named/<your_domain>.sa.cs.ut.ee
    • here <your_domain> is your personal domain name

If command reports no error, the Zone file is correct

If the zone file is correct we may add the defined zone into bind configuration.

Edit the named configuration, the one containing the declared zone "." IN .

  • Underneath the zone "." IN declaration add a new zone clause
    • having zone name set to your personal domain
    • pointing to the previously defined
    • having type master

In our examples we made it as follows:

...
zone "student-test.sa.cs.ut.ee" IN {
        type master;
        file "/etc/named/student-test.sa.cs.ut.ee";
        allow-update { none; };
};

After editing configuration, do not forget to check if it is valid, using named-checkconf command

If the configuration is OK:

  • Restart the named service
  • Make sure it did load the new zone (check the named log file)
    • /var/named/log/default

The log has to have line like:

...
08-Mar-2020 16:35:58.841 general: info: zone student-test.sa.cs.ut.ee/IN: loaded serial 2020030804
08-Mar-2020 16:35:58.841 general: notice: all zones loaded
08-Mar-2020 16:35:58.841 general: notice: running...
...

Afterwards you should be able to use dig or nslookup commands for testing:

  • $ dig @127.0.0.1 <your_domain>
  • $ dig @127.0.0.1 ns1.<your_domain>
  • $ dig @127.0.0.1 <your_domain> NS

Might happen, that some of the queries return ANSWER: 0? Can you explain that?

  • Add notify explicit; to your personal zone statement in the DNS server configuration file.
  • Add also-notify { 172.17.66.134; }; to the configuration file under options.
  • Increment your zone's serial by one.
  • Restart your named service.

Rerun the queries:

  • $ dig @127.0.0.1 <your_domain>
  • $ dig @127.0.0.1 ns1.<your_domain>
  • $ dig @127.0.0.1 <your_domain> NS

The dig should show result properly:

Example dig result of the command:

  • dig @127.0.0.1 student-test.sa.cs.ut.ee
; <<>> DiG 9.11.4-P2-RedHat-9.11.4-26.P2.el8 <<>> @127.0.0.1 student-test.sa.cs.ut.ee
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 64197
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 2

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
; COOKIE: 5b6c2462c45d2d8c86684aec5e65045a42fab1a5ec27af6a (good)
;; QUESTION SECTION:
;student-test.sa.cs.ut.ee.		IN	A

;; ANSWER SECTION:
student-test.sa.cs.ut.ee.	900	IN	A	172.17.65.65

;; AUTHORITY SECTION:
student-test.sa.cs.ut.ee.	900	IN	NS	ns1.student-test.sa.cs.ut.ee.

;; ADDITIONAL SECTION:
ns1.student-test.sa.cs.ut.ee.	900	IN	A	172.17.65.65

;; Query time: 2 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Sun Mar 08 16:42:34 EET 2020
;; MSG SIZE  rcvd: 125

What notify explicit; does, is that it forces the DNS server to notify slave DNS servers about updates. Without it might happen, that other DNS servers do not pick up updates to your domain before the end of TTL time, which can take very long sometimes.

Understanding reverse mapping Zone files

The interesting fact about records in Zone file configurations:

  • all the associations are unidirectional

which means if we have

  • ns1.example.org. A IN 10.10.10.5

it is equivalent to the link

  • ns1.example.org. -> 10.10.10.5

and not opposite way around:

  • 10.10.10.5 -> ns1.example.org.

The secondary link from IP to the host name has to be added by introducing the PTR records. The PTR records are organized and collected in separate Zone file called Reverse Mapped Zone.

Why can't we just put PTRs in same Zone file we created in previous tasks?

You already know the DNS name space is organized in hierarchical structure:

The whole domain name space is first addressed from root(.) which is the root of the whole DNS tree, then it's divided across number of TLDs, like .com, .org, .net etc. You can check the full list of TLDs here. Next, each TLD has a number of sub-domain and for us we did introduce additional TLD <name>.sa.cs.ut.ee with sub-domains for each student. Following the divide and conquer idea each of the sub-domains can further be divided in sub-domains (each student can potentially create an infinite amount of sub-domains).

Considering the TLDs once again there is one specific: .arpa which currently isn't serving any of the domains, but is holding routing and addressing parameters and is therefore called Infrastructure TLD.

  • The DNS architecture was designed by US Advanced Research Project Agency (ARPA)
  • .arpa was originally domain name of the ARPA agency, and it was the first domain introduce in DNS name space.
  • as it turned to be Infra-TLD the .arpa is referred as Addressing and Routing Parameter Area.

The idea behind .arpa Infra-TLD is to provide reverse mappings (from IP to host name), and is mainly used by humans for such things as tracking where a web-site visitor came from, or where an e-mail message originated etc.

However reverse DNS is important for one particular application. Many e-mail servers on the Internet are configured to reject incoming e-mails from any IP address which does not have reverse DNS. So if you run your own e-mail server, reverse DNS must exist for the IP address that outgoing e-mail is sent from. Reverse DNS mappings are also an important part of keeping the trust-based DNS working. A simple check any service provider can run is looking for mismatches in PTR and A type records, and usually if these don't match data is marked as spam.

The IPv4 address space is of course not infinite but the idea of hierarchy is followable if we consider how the IPv4 space is divided into subnets. Each organization is assigned with a big subnet (A class or B class dependent on the size of the organization). Dependent on the inner structure of the organization the big subnet can be divided again and again till there are free unused IPv4 addresses.

As you can see, the bigger subnets can still be broken into smaller ones, the simple example is explained here (if you struggle understanding concepts of IP addressing you may first read the IP Basics). Now, taking this into account, all of the IP address space was structured and reduced into reverse mapping Zones under the .arpa TLD. Therefore the .arpa is broken into sub-domains as follows:

  • in-addr.arpa domain contains all the reverse mappings for IPv4 address space (in-addr stands for Internet Address)
  • in-ip6.arpa domain contains all the reverse mappings for IPv6 address space

Now each of them is broken down into sub-domains denoting subnets of IPv4 or IPv6. The domain name for the subnet is then constructed as follows:

  • For the IPv4 subnet:
    • Consider your subnet (for example you have 172.17.6.0/24)
    • The non-changeable part is 172.17.6. (by subnet 172.17.6.0) and only the last octet can change (by netmask 255.255.255.0)
    • Non-changeable part is then reversed (so we get 6.17.172)
    • in-addr.arpa is appended to the reversed subnet (we get 6.17.172.in-addr.arpa)
    • 6.17.172.in-addr.arpa is then our domain for reverse mapping:
      • This will be the $ORIGIN for the reverse mapping Zone file
  • For the IPv6 subnet:
    • ... to be added ...

Now the reverse mapping Zone files are similar to regular Zone files, here is an example:

$ORIGIN 6.17.172.in-addr.arpa.   ; Zone starting point in the name-space tree
                     ; (if skipped - the origin is inferred by the DNS server based on
                     ; zone declaration in name.conf.local file
$TTL 15M             ; Default expiration time for all resources
@ IN SOA ns.domain-example.org. root.domain-example.org.(
	 2012020101       ; Serial
		15M       ; Refresh (15 minutes)
		5M        ; Retry (5 minutes)
		604800    ; Expire (7 days in seconds)
		600 )     ; Negative Cache TTL
@              IN      NS      ns.domain-example.org.       ; Name Server for domain-example.org
1             IN      PTR     ns.domain-example.org.       ; 172.17.6.1 has name ns.domain-example.org
5             IN      PTR     myhost.domain-example.org.   ; 172.17.6.5 has name myhost.domain-example.org
6             IN      PTR     mail.domain-example.org.     ; 172.17.6.6 has name mail.domain-example.org
7             IN      PTR     myhost2.domain-example.org.  ; 172.17.6.7 has name myhost2.domain-example.org

As you can see there is not much changed in the headers:

  • $ORIGIN - pointing to 17.172.in-addr.arpa
    • we can omit specifying origin, leaving it for bind9 to specify it (inferring named.conf.local configurations
  • TTL and SOA records remain the same as in regular Zone file (we are still in domain-example.org)
  • NS record is the same (we are still having DNS server's FDQN: ns.domain-example.org.)
  • Next we have the PTR record for each A or AAAA type of records from the regular Zone file of our domain
    • Each host name -> IP association should have a reverse association IP -> host name.

Please note, that it is possible to specify multiple A or AAAA types of record pointing to the same IP address, however in reverse mapping only one of the host names may be pointed by the PTR type of record. For example, in the regular Zone file we have:

@       IN      A       172.17.6.1    ; IPv4 address for domain-example.org
ns      IN      A       172.17.6.1    ; IPv4 address for ns.domain-example.org

Both domain-example.org and ns.domain-example.org are having the A type of record pointing to the same IP of 172.17.6.1. In the reverse mappings however we have only one record:

1             IN      PTR     ns.domain-example.org.

... saying 172.17.6.1 has name ns.domain-example.org Please keep in mind this is an example. For you it needs to be a different IP address.

The content of reverse mapping Zone file is then stored similar to regular Zone:

  • Zone example-domain.org was stored in file example-domain.org.zone
  • Zone 6.17.172.in-addr.arpa should be stored in file 6.17.172.in-addr.arpa.zone

The file name convention is not important to follow (you can use other names if you wish), the idea of this convention is to keep named.conf.local configuration file more clear and followable.

The last thing to understand is how the reverse mapping Zone file is embedded into existing bind9 configuration, and this is fact 1-to-1 similar to how we declared the regular Zone in bind9 configuration (we have to add another zone clause in the configuration file):

  • We cannot reuse existing zone clause domain-example.org for the reversed one 6.17.172.in-addr.arpa

Can you now explain why ? If you struggle with an answer think about the following: What is the $ORIGIN variable? How is it assigned? How is it related to domain name? How does the DNS name space look like? What is TLD? What is Infrastructure TLD? Which part of DNS name space is responsible for direct lookup queries? Which part of DNS name space is responsible for reverse lookup queries?

After answering those questions it should be clear - the reverse mappings we can only specify under .arpa infrastructure TLD; which separate branch of DNS name space (not overlapping with .org TLD). Therefore the $ORIGIN is different too, and has to be declared separately.

Declaring the zone clause for reverse mapping Zone is then looking like:

zone "65.17.172.in-addr.arpa" IN {
        type master;
        file "/etc/named/reverse.student-test.sa.cs.ut.ee";
        allow-update { none; };
};

Is it by the way important to specify

  • allow-update { none; };

After the reverse mapping Zone file is included in bind configuration, the standard check-routines should follow:

  • Checking the reverse mapping Zone file:
    • named-checkzone ''65.17.172.in-addr.arpa'' <path to reverse.student-test.sa.cs.ut.ee file>
  • Checking the named configuration using named-checkconf command

Now we are ready to add the reverse mapping Zone to our bind9 configuration for our network and to populate it with PTR records.

Create the reverse mapping Zone file for 172.17.X.X/24:

  • use the same $TTL and $SOA as in the regular Zone file you created for your domain
  • add the required PTR records
    • if you do not know what to add, please refer to the Understanding reverse mapping Zone files'
  • save the reverse mapping file
    • into the same directory as the regular Zone file you created for your domain
    • select the proper file name, try to follow the conventions we have explained
    • make sure the Zone file has proper ownership and permissions
  • check the Zone file using named-checkzone command
    • the example was given before

If the reverse mapping Zone is OK, construct the reverse mapping domain name:

  • The example how to get reverse domain name from IPv4 subnet was given before

If you have calculated the reverse mapping name for your subnet:

Edit the bind9 local configuration file:

  • find the proper place to add new zone clause
  • add new zone clause having:
    • zone name properly assigned with reverse mapping domain name you have calculated
    • file - assigned with absolute path of the corresponding file containing reverse mappings
    • type - assigned to master
  • save the configuration file

Check the configuration using corresponding command

If the configuration is OK:

Restart the DNS service

Check if reverse mapping is working properly using the following command:

  • host <your external-IP address>
  • nslookup <your external-IP address>
    • It should give you back the FQDN you assigned to IP address

8. Ansible - automating the above

The focal point of the DNS lab for Ansible is mostly getting comfortable with template module. There is also the copy module. But due to the usability aspect of templates it is suggested to utilize heavily the template module.

You are not obliged to use templating if copy module suits you more, but read this artcile from Anthony Critelli at redhat.com to give you a proper distinction between the two.

TL;DR version: Copy module copies files from local host to remote host that you want to manage. Template module also copies files from local host to remote host but allows you to dynamically change the template's content through variables, Jinja2 is the magic behing template module.

Let's start by making sure the structure is there:

  • Create a new directory called dns under your roles directory.
  • Into the newly created dns create two directories tasks and templates
    • We will start putting all of the templated files into the templates directory
  • Finally, create main.yml into the tasks directory.

Something like this:

|
|- playbook.yml
|- roles/
|    |- dns
|    |   |- templates
|    |   |- tasks
|    |        |- main.yml
...

You should now start populating the roles/dns/tasks/main.yml file. The following example is written for you based on the above lab manual. The general idea is that once you know how to manually for example disable IPv6 in the lab vm you should immediately write it into your playbook. The following example has been purposefully left halfway done, it is here to get you started.

Add this to your main.yml file under roles/dns/tasks/:

---
- name: DNS | Autoremove unneeded packages installed as dependencies
  dnf:
    autoremove: yes
  tags:
    - dns

- name: Disable IPv6
  copy:
    src: 70-ipv6.conf
    dest: /etc/sysctl.d/70-ipv6.conf
    owner: root
    group: root
    mode: '0644'
  tags:
    - dns

- name: Change net.ipv6.conf.default.disable_ipv6 to 1.
  sysctl:
    name: net.ipv6.conf.default.disable_ipv6
    value: '1'
    sysctl_file: /etc/sysctl.d/70-ipv6.conf
    reload: yes
  tags:
    - dns

- name: Change net.ipv6.conf.all.disable_ipv6 to 1.
  sysctl:
    name: net.ipv6.conf.all.disable_ipv6
    value: '1'
    sysctl_file: /etc/sysctl.d/70-ipv6.conf
    reload: yes
  tags:
    - dns

- name: Inserts into hostname
  template:
    src: hostname.j2
    dest: /etc/hostname
    owner: root
    group: root
    mode: '0644'
  tags:
    - dns

- name: Inserts into hosts
  template:
    src: hosts.j2
    dest: /etc/hosts
    owner: root
    group: root
    mode: '0644'
  tags:
    - dns 

From the piece of dns role above you should have figured out, that we are going to need to create more files and directories into our ansible playbook directory. To make our directory tree look like this:

|
|- playbook.yml
|- roles/
|    |- dns
|    |   |- templates
|    |   |    |- hostname.j2
|    |   |    |- hosts.j2
|    |   |
|    |   |- files
|    |   |    |- 70-ipv6.conf
|    |   |       
|    |   |- tasks
|    |        |- main.yml
...

In the below todo box you will notice wierd syntax {{ hostname }}, {{ domain_name }}. These are called variables in Ansible. They serve as place holders for infomation you would like to insert every time the playbook runs. Using variables in this case is useful for testing purposes, as you can run your playbook over and over again and monitor how the variable gets placed into the destination. Having {{ hostname }} and {{ domain_name }} as variables is useful for the lifecycle of this playbook, as during the exam, these variables could change.

  • Create an empty file 70-ipv6.conf under the files directory.
  • Create empty files hostname.j2 and hosts.j2 under the templates directory.
  • Edit the 70-ipv6.conf file and copy the following into it:
net.ipv6.conf.default.disable_ipv6=1
net.ipv6.conf.all.disable_ipv6=1
  • Edit the hosts.j2 file and change its content to match the following:
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
127.0.1.1   {{ hostname }}.{{ domain_name }} {{ hostname }}
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
  • Edit the hostname.j2 and replace it's content with this:
{{ hostname }}.{{ domain_name }}

So far we have created the tree structure for our role and populated the files in the dns role. To make use of the variables, we need to define them also. A good place for that is the main playbook file.

  • Add variables hostname and domain_name to your playbook.
  • Add the dns role declaration to your playbook.
---
- hosts: sa-vm
  user: centos
  become: yes
  become_method: sudo
  become_user: root
  vars:
    hostname: student-test
    domain_name: sa.cs.ut.ee

  roles:
   - { role: lab1, tags: lab1 } 
   - { role: dns, tags: dns }
  • Run your playbook !
  • Make sure playbook has done everything as you have declared / described in yaml format.
    • It is a good idea check if every permission and owner and file is where it should be after the first run of the playbook.

The piece of playbook above does not cover the whole lab. That was not the point of this section. The point of this section was to get you started writing your own role for this lab. From this point onward you should use template or copy module for these files: <your_domain>, reverse.<your_domain> , resolv.conf, named.conf. You should use systemd module to restart named.

One final hint for this lab. Figure out what it does and use it, if you find it useful.

- name: Command host {{ ip_address }}
  command: host {{ ip_address }}
  register: host_output

- name: Debug host {{ ip_address }} output
  debug:
    var: host_output

9. Keeping your Ansible repository safe in our Gitlab

And as always push your stuff to our Gitlab.

  • In your ansible home directory:
  • git add .
  • git commit -m "DNS lab"
  • git push -u origin master

Go to your gitlab page in to see all of your latest push reached the git repository. If you play around with your repository and have made changes to the ansible that you wish to utilize also in the future, always remember to commit and push them.

  • Arvutiteaduse instituut
  • Loodus- ja täppisteaduste valdkond
  • Tartu Ülikool
Tehniliste probleemide või küsimuste korral kirjuta:

Kursuse sisu ja korralduslike küsimustega pöörduge kursuse korraldajate poole.
Õppematerjalide varalised autoriõigused kuuluvad Tartu Ülikoolile. Õppematerjalide kasutamine on lubatud autoriõiguse seaduses ettenähtud teose vaba kasutamise eesmärkidel ja tingimustel. Õppematerjalide kasutamisel on kasutaja kohustatud viitama õppematerjalide autorile.
Õppematerjalide kasutamine muudel eesmärkidel on lubatud ainult Tartu Ülikooli eelneval kirjalikul nõusolekul.
Courses’i keskkonna kasutustingimused