Palvelinten hallinta - Harjoitus 2
==============

*Disclaimer:*
--------------

Tämä harjoitus on tehty osana Haaga-Helian Tietojenkäsittelyn koulutusohjelman kurssia [Palvelinten hallinta (ICT4TN022, kevät 2018)](http://www.haaga-helia.fi/fi/opinto-opas/opintojaksokuvaukset/ICT4TN022). Kurssin pitäjänä toimii [Tero Karvinen](http://terokarvinen.com/), joka on määritellyt tämän harjoituksen tehtävänkuvaukset. Tehtävien vastaukset ovat Pekka Heleniuksen (allekirjoittanut) tuottamia.

*SISÄLLYSLUETTELO*
--------------

- [b) Laita käyttäjien kotisivut toimimaan Apachella - Salt](https://github.com/Fincer/central-management-of-multiple-servers/blob/master/h2.md#b-laita-k%C3%A4ytt%C3%A4jien-kotisivut-toimimaan-apachella---salt)

- [c) Laita PHP toimimaan käyttäjien kotisivuilla - Salt (Huomaa, että PHP toimii oletuksena kaikkialla muualla kuin käyttäjien public_html-kotisivuilla.)](https://github.com/Fincer/central-management-of-multiple-servers/blob/master/h2.md#c-laita-php-toimimaan-k%C3%A4ytt%C3%A4jien-kotisivuilla---salt-huomaa-ett%C3%A4-php-toimii-oletuksena-kaikkialla-muualla-kuin-k%C3%A4ytt%C3%A4jien-public_html-kotisivuilla)

- [d) Rakenna tila (state), joka tekee Apachelle uuden nimipohjaisen virtuaalipalvelimen (name based virtual hosting). Voit simuloida nimipalvelun toimintaa hosts-tiedoston avulla.](https://github.com/Fincer/central-management-of-multiple-servers/blob/master/h2.md#d-rakenna-tila-state-joka-tekee-apachelle-uuden-nimipohjaisen-virtuaalipalvelimen-name-based-virtual-hosting-voit-simuloida-nimipalvelun-toimintaa-hosts-tiedoston-avulla)

- [e) Tee tila, joka laittaa esimerkkikotisivun uusille käyttäjille. Voit laittaa esimerkkikotisivu /etc/skel/:iin, niin se tulee automaattisesti ‘adduser tero’ komennolla käyttäjiä luodessa.](https://github.com/Fincer/central-management-of-multiple-servers/blob/master/h2.md#e-tee-tila-joka-laittaa-esimerkkikotisivun-uusille-k%C3%A4ytt%C3%A4jille-voit-laittaa-esimerkkikotisivu-etcskeliin-niin-se-tulee-automaattisesti-adduser-tero-komennolla-k%C3%A4ytt%C3%A4ji%C3%A4-luodessa)

- [f) Eri asetukset. Tee Package-File-Service tilalla eri asetuksia kuin ne, mitä tehtiin tunnilla; ja eri kuin mitä teit/teet h2 muissa kohdissa. Voit muuttaa jotain toista asetusta samoista demoneista tai valita kokonaan eri demonit.](https://github.com/Fincer/central-management-of-multiple-servers/blob/master/h2.md#f-eri-asetukset-tee-package-file-service-tilalla-eri-asetuksia-kuin-ne-mit%C3%A4-tehtiin-tunnilla-ja-eri-kuin-mit%C3%A4-teitteet-h2-muissa-kohdissa-voit-muuttaa-jotain-toista-asetusta-samoista-demoneista-tai-valita-kokonaan-eri-demonit)

b) Laita käyttäjien kotisivut toimimaan Apachella - Salt
--------------

**Vastaus:**

Olemme tässä vaiheessa luoneet perusedellytykset Masterille ja Minione(ille). Ks. [harjoitus 1](https://github.com/Fincer/central-management-of-multiple-servers/blob/master/h1.md)

Luodaan Master-koneen kansioon _/srv/salt_ state-tiedosto *0_create_indexhtml.sls* komennolla *sudo nano /srv/salt/0_create_indexhtml.sls* ja täydennetään se sisällöllä:

```
# This is a Salt script for installing Apache HTTP daemon with
# default userdir configuration to minion computers
# Author: Pekka Helenius (~Fincer), 2018

#########################################
# Install Apache HTTP daemon to minions

install_httpd_daemon:
  pkg.installed:
    - pkgs:
      - apache2

#########################################
# Enable Apache userdir module

httpd_userdir:
  cmd.run:
    - name: /usr/sbin/a2enmod userdir
    - require:
      - pkg: install_httpd_daemon

#########################################
# Replace default index.html content

httpd_foo-index:
  cmd.run:
    - name: /bin/echo "foo" > /var/www/html/index.html
    - require:
      - cmd: httpd_userdir
      - pkg: install_httpd_daemon

#########################################
# Execute public_html script

execute_public_html:
  cmd.script:
    - name: salt://0_create_indexhtml.sh
    - runas: root

#########################################
# Restart Apache HTTP daemon

httpd_service_restart_userdir:
  service.running:
    - name: apache2.service
    - watch:
      - cmd: httpd_userdir

``` 

Tiedoston oikeudet tulisi olla: u=rw, g=r, o=r (0644)

Harjoituksessa käytetään Debian-pohjaisia Xubuntu-käyttöjärjestelmiä (18.04 LTS).

Varmistetaan, että "orja" -alkuisiin orjakoneisiin (minions) saadaan yhteys suorittamalla master-koneella esim. komento:

```
[09/04/2018 22:01:26 - fincer: ~ ]$ sudo salt 'orja*' grains.item osrelease
orjakone:
    ----------
    osrelease:
        18.04
```

Luodaan master-koneelle seuraava shell-skripti */srv/salt/0_create_indexhtml.sh*, joka tuottaa kaikille orjakoneen käyttäjille kansion *public_html* testisivuineen:

```
#!/bin/sh

# Find home folders of system users (who are using bash as their default shell)
for userhome in $(grep -E "\/bin\/bash" /etc/passwd | grep -v root | awk -F ':' '{print $(NF - 1)}'); do

    # Create public_html for found user
    if [ ! -d "${userhome}"/public_html ]; then
      mkdir -p "${userhome}"/public_html

      # Promote this user to be the owner of the created directory
      chown $(stat --format "%u:%g" ${userhome}) "${userhome}"/public_html

      # Touch default index file for testing purposes
      echo "This is my test site. I am user $(stat --format \"%U\" ${userhome}). Happy coding!" > "${userhome}"/public_html/index.html
    fi

done
```

Suoritetaan tehtävänannossa edellytetty Apache HTTP-daemonin asennus minion-koneille:

```
sudo salt 'orja*' state.apply 0_create_indexhtml
```

Esimerkki-output (masterilla):

```
[09/04/2018 21:45:41 - fincer: salt ]$ sudo salt 'orja*' state.apply 0_create_indexhtml
orjakone:
----------
          ID: install_httpd_daemon
    Function: pkg.installed
      Result: True
     Comment: All specified packages are already installed
     Started: 03:06:06.583325
    Duration: 377.198 ms
     Changes:   
----------
          ID: httpd_userdir
    Function: cmd.run
        Name: /usr/sbin/a2enmod userdir
      Result: True
     Comment: Command "/usr/sbin/a2enmod userdir" run
     Started: 03:06:06.962361
    Duration: 19.784 ms
     Changes:   
              ----------
              pid:
                  20406
              retcode:
                  0
              stderr:
              stdout:
                  Module userdir already enabled
----------
          ID: httpd_foo-index
    Function: cmd.run
        Name: /bin/echo "foo" > /var/www/html/index.html
      Result: True
     Comment: Command "/bin/echo "foo" > /var/www/html/index.html" run
     Started: 03:06:06.982499
    Duration: 3.978 ms
     Changes:   
              ----------
              pid:
                  20411
              retcode:
                  0
              stderr:
              stdout:
----------
          ID: execute_public_html
    Function: cmd.script
        Name: salt://0_create_indexhtml.sh
      Result: True
     Comment: Command 'salt://0_create_indexhtml.sh' run
     Started: 03:06:06.986594
    Duration: 415.176 ms
     Changes:   
              ----------
              pid:
                  20432
              retcode:
                  0
              stderr:
              stdout:
----------
          ID: httpd_service_restart_userdir
    Function: service.running
        Name: apache2.service
      Result: True
     Comment: Service restarted
     Started: 03:06:07.435663
    Duration: 124.998 ms
     Changes:   
              ----------
              apache2.service:
                  True

Summary for orjakone
------------
Succeeded: 5 (changed=4)
Failed:    0
------------
Total states run:     5
Total run time: 941.134 ms
```

Minion-koneelta voimme tarkastaa, onko kansio *public_html* ja tiedosto *index.html* luotu (esim. orjakone:en käyttäjälle fincer):

```
[09/04/2018 21:46:59 - fincer: salt ]$ sudo salt 'orjakone' cmd.run 'cat /home/fincer/public_html/index.html'
orjakone:
    This is my test site. I am user "fincer". Happy coding!
```

c) Laita PHP toimimaan käyttäjien kotisivuilla - Salt (Huomaa, että PHP toimii oletuksena kaikkialla muualla kuin käyttäjien public_html-kotisivuilla.)
--------------

**Vastaus:**

Tehtävässä pitää orjakoneilta (minions) kytkeä PHP päälle userdir-moduulin kanssa editoimalla konfiguraatiotiedostoa /etc/apache2/mods-available/php*.conf (missä * on php-versio).
Tämä vaihe voidaan tehdä kahdella tavalla:

- 1) Luodaan master-koneelle uusi konfiguraatiotiedosto (php*.conf) samalla sisällöllä, mutta kommentoidaan userdir-moduulin edellyttämät rivit tiedostosta (tiedostossa on selkeät ohjeet tähän)

- 2) Luodaan skripti, jonka tehtävänä on lisätä kommenttimerkit orjakoneiden php*.conf -tiedoston relevanttiin osioon

Molemmat vaihtoehdot määritetään suoritettavaksi master:lla Saltin state-tiedostossa. Toteutetaan vaihtoehto 2.

Luodaan master-koneella shell-skripti */srv/salt/1_enable_php-for-userdir.sh* sisällöllä:

```
#!/bin/sh

# Enable PHP for userdir module in Apache
# Author: Pekka Helenius, 2018

PHP_CONF_FILE="$(ls /etc/apache2/mods-available/php*.conf)"

IFS="
"

for line in $(cat "${PHP_CONF_FILE}" | sed -n '/\<IfModule mod_userdir\.c>/,/\<\/IfModule>/p;/\<\/IfModule>/q'); do
    sed_line=$(echo "${line}" | sed 's!\*!\\*!g;')
    sed -ir "s!${sed_line}!#${sed_line}!" "${PHP_CONF_FILE}"
done

unset IFS

```

Luodaan master-koneella toinenkin shell-skripti */srv/salt/1_create_indexphp.sh* seuraavalla sisällöllä:

```
#!/bin/sh

# Find home folders of system users (who are using bash as their default shell)
for userhome in $(grep -E "\/bin\/bash" /etc/passwd | grep -v root | awk -F ':' '{print $(NF - 1)}'); do

    # Create public_html for found user
    if [ ! -d "${userhome}"/public_html ]; then
      mkdir -p "${userhome}"/public_html

      # Promote this user to be the owner of the created directory
      chown $(stat --format "%u:%g" ${userhome}) "${userhome}"/public_html

      # Rename existing index.html if exists
      if [ -f "${userhome}"/public_html/index.html ]; then
        mv "${userhome}"/public_html/index.html "${userhome}"/public_html/index.html.old
      fi

      # Touch default index PHP file for testing purposes
      echo "<?php print('This is PHP code. I am user $(stat --format \"%U\" ${userhome}). Happy coding!'); ?>" > "${userhome}"/public_html/index.php
    fi

done

```

Luodaan master-koneelle state-määritystiedosto */srv/salt/1_create_indexphp.sls* sisällöllä:

```
# Author: Pekka Helenius (~Fincer), 2018

#########################################
# Variables

# PHP module for Apache in Debian
{% set ENABLE_PHP_MODULE = "/usr/sbin/a2enmod $(a2query -m | awk '{print $1}' | grep php)" %}

{% set USERDIR_ENABLE_STATUS = "a2query -m | grep userdir | grep 'enabled by' &>/dev/null || /usr/sbin/a2enmod userdir" %}

#########################################
# Install PHP addons for Apache HTTP daemon (with dependencies)

install_httpd_php:
  pkg.installed:
    - pkgs:
      - apache2
      - libapache2-mod-php

#########################################
# Find if userdir module is enabled

check_userdir_status:
  cmd.run:
    - name: {{ USERDIR_ENABLE_STATUS }}
    - require:
      - pkg: install_httpd_php

#########################################
# Enable PHP for users

execute_userdir_php_script:
  cmd.script:
    - name: salt://apache/1_enable_php-for-userdir.sh
    - runas: root
    - require:
      - cmd: check_userdir_status

add_indexphp_files:
  cmd.script:
    - name: salt://apache/1_create_indexphp.sh
    - runas: root
    - require:
      - cmd: execute_userdir_php_script

#########################################
# Enable PHP module (should be done already, though)

enable_httpd_php:
  cmd.run:
    - name: {{ ENABLE_PHP_MODULE }}

#########################################
# Restart Apache HTTP daemon

httpd_service_restart_php:
  service.running:
    - name: apache2.service
    - watch:
      - cmd: check_userdir_status
      - cmd: execute_userdir_php_script

```

Esimerkki-output master-koneella:

```
[09/04/2018 23:13:27 - fincer: ~ ]$ sudo salt 'orjakone' state.apply 1_create_indexphp
orjakone:
----------
          ID: install_httpd_php
    Function: pkg.installed
      Result: True
     Comment: All specified packages are already installed
     Started: 03:12:05.777863
    Duration: 387.502 ms
     Changes:   
----------
          ID: check_userdir_status
    Function: cmd.run
        Name: a2query -m | grep userdir | grep 'enabled by' &>/dev/null || /usr/sbin/a2enmod userdir
      Result: True
     Comment: Command "a2query -m | grep userdir | grep 'enabled by' &>/dev/null || /usr/sbin/a2enmod userdir" run
     Started: 03:12:06.167690
    Duration: 37.4 ms
     Changes:   
              ----------
              pid:
                  20663
              retcode:
                  0
              stderr:
              stdout:
                  userdir (enabled by site administrator)
----------
          ID: execute_userdir_php_script
    Function: cmd.script
        Name: salt://1_enable_php-for-userdir.sh
      Result: True
     Comment: Command 'salt://1_enable_php-for-userdir.sh' run
     Started: 03:12:06.206077
    Duration: 192.94 ms
     Changes:   
              ----------
              pid:
                  20690
              retcode:
                  0
              stderr:
              stdout:
----------
          ID: add_indexphp_files
    Function: cmd.script
        Name: salt://1_create_indexphp.sh
      Result: True
     Comment: Command 'salt://1_create_indexphp.sh' run
     Started: 03:12:06.399689
    Duration: 142.251 ms
     Changes:   
              ----------
              pid:
                  20734
              retcode:
                  0
              stderr:
              stdout:
----------
          ID: enable_httpd_php
    Function: cmd.run
        Name: /usr/sbin/a2enmod $(a2query -m | awk '{print $1}' | grep php)
      Result: True
     Comment: Command "/usr/sbin/a2enmod $(a2query -m | awk '{print $1}' | grep php)" run
     Started: 03:12:06.542066
    Duration: 68.876 ms
     Changes:   
              ----------
              pid:
                  20741
              retcode:
                  0
              stderr:
              stdout:
                  Considering dependency mpm_prefork for php7.2:
                  Considering conflict mpm_event for mpm_prefork:
                  Considering conflict mpm_worker for mpm_prefork:
                  Module mpm_prefork already enabled
                  Considering conflict php5 for php7.2:
                  Module php7.2 already enabled
----------
          ID: httpd_service_restart_php
    Function: service.running
        Name: apache2.service
      Result: True
     Comment: Service restarted
     Started: 03:12:06.635009
    Duration: 87.188 ms
     Changes:   
              ----------
              apache2.service:
                  True

Summary for orjakone
------------
Succeeded: 6 (changed=5)
Failed:    0
------------
Total states run:     6
Total run time: 916.157 ms
```

d) Rakenna tila (state), joka tekee Apachelle uuden nimipohjaisen virtuaalipalvelimen (name based virtual hosting). Voit simuloida nimipalvelun toimintaa hosts-tiedoston avulla.
--------------

**Vastaus:**

**HUOM!** Tämän olisi voinut tehdä myös luomalla esim. index.html- ja sivustokonfiguraatiotiedostot masterilla, josta ne siirrettäisiin minioneille (file). Nämä määritykset tehdään state-tiedostossa, luonnollisesti. Paljon parempi tapa, jos on esimerkiksi tarkoitus laittaa juuri samansisältöinen _/etc/apache2/sites-available/*.conf_ -tiedosto/template ja samansisältöinen, masterilta päivitettävissä oleva index.html -tiedosto minioneille. Tein nyt huvikseni seuraavalla tavalla, vaikka tiedän, ettei se nyt ihan nappiin menekkään.

Luodaan master-koneen */srv/salt/* -kansioon state/konfiguraatiotiedosto *apache_virtualhost_example.sls* sisällöllä:

```
# Author: Pekka Helenius (~Fincer), 2018

#########################################
# Install Apache HTTP daemon to minions

install_httpd_daemon:
  pkg.installed:
    - pkgs:
      - apache2

#########################################

copy_httpd_defaultsite:
  cmd.run:
    - name: '[ ! -f /etc/apache2/sites-available/$(hostname)-example.conf ] && cd /etc/apache2/sites-available && cp 000-default.conf $(hostname)-example.conf || false'
    - require:
      - pkg: install_httpd_daemon

create_site_rootdir:
  cmd.run:
    - name: /bin/mkdir -p /var/www/html/$(hostname)
    - require:
      - pkg: install_httpd_daemon

enable_httpd_servername:
  cmd.run:
    - name: /bin/sed -i "s/#ServerName www\.example\.com/ServerName $(hostname).example.com/" /etc/apache2/sites-available/$(hostname)-example.conf
    - require:
      - cmd: copy_httpd_defaultsite

change_defaultsite_root:
  cmd.run:
    - name: /bin/sed -i "s/DocumentRoot \/var\/www\/html/DocumentRoot \/var\/www\/html\/$(hostname)/" /etc/apache2/sites-available/$(hostname)-example.conf
    - require:
      - cmd: enable_httpd_servername

enable_httpd_defaultsite:
  cmd.run:
    - name: /usr/sbin/a2ensite $(hostname)-example.conf
    - require:
      - cmd: change_defaultsite_root
      - cmd: copy_httpd_defaultsite
      - pkg: install_httpd_daemon 

add_virtualhost_string:
  cmd.run:
    - name: /bin/echo "127.0.0.1 $(hostname).example.com" > /etc/hosts
    - require:
      - cmd: enable_httpd_defaultsite

add_defaultsite_indexfile:
  cmd.run:
    - name: '[ ! -f /var/www/html/$(hostname)/index.html ] && /bin/echo "This is default HTML template for $(hostname) ($(hostname).example.com), created on $(date \"+%d-%m-%Y at %X\")" > /var/www/html/$(hostname)/index.html'
    - require:
      - cmd: create_site_rootdir
      - cmd: add_virtualhost_string
      - cmd: enable_httpd_defaultsite

restart_httpd_service:
  service.running:
    - name: apache2.service
    - watch:
      - cmd: enable_httpd_defaultsite
      - cmd: add_defaultsite_indexfile
```

Ajetaan em. state masterilta minion-koneelle nimeltä "orjakone" (vain tälle yhdelle koneelle, ei muita orjia nyt!):

```
[10/04/2018 00:13:12 - fincer: ~ ]$ sudo salt 'orjakone' state.apply apache_virtualhost_example
orjakone:
----------
          ID: install_httpd_daemon
    Function: pkg.installed
      Result: True
     Comment: All specified packages are already installed
     Started: 05:20:27.160570
    Duration: 360.254 ms
     Changes:   
----------
          ID: copy_httpd_defaultsite
    Function: cmd.run
        Name: [ ! -f /etc/apache2/sites-available/$(hostname)-example.conf ] && cd /etc/apache2/sites-available && cp 000-default.conf $(hostname)-example.conf || false
      Result: False
     Comment: Command "[ ! -f /etc/apache2/sites-available/$(hostname)-example.conf ] && cd /etc/apache2/sites-available && cp 000-default.conf $(hostname)-example.conf || false" run
     Started: 05:20:27.522609
    Duration: 4.361 ms
     Changes:   
              ----------
              pid:
                  22444
              retcode:
                  1
              stderr:
              stdout:
----------
          ID: create_site_rootdir
    Function: cmd.run
        Name: /bin/mkdir -p /var/www/html/$(hostname)
      Result: True
     Comment: Command "/bin/mkdir -p /var/www/html/$(hostname)" run
     Started: 05:20:27.527146
    Duration: 3.26 ms
     Changes:   
              ----------
              pid:
                  22446
              retcode:
                  0
              stderr:
              stdout:
----------
          ID: enable_httpd_servername
    Function: cmd.run
        Name: /bin/sed -i "s/#ServerName www\.example\.com/ServerName $(hostname).example.com/" /etc/apache2/sites-available/$(hostname)-example.conf
      Result: False
     Comment: One or more requisite failed: apache_virtualhost_example.copy_httpd_defaultsite
     Changes:   
----------
          ID: change_defaultsite_root
    Function: cmd.run
        Name: /bin/sed -i "s/DocumentRoot \/var\/www\/html/DocumentRoot \/var\/www\/html\/$(hostname)/" /etc/apache2/sites-available/$(hostname)-example.conf
      Result: False
     Comment: One or more requisite failed: apache_virtualhost_example.enable_httpd_servername
     Changes:   
----------
          ID: enable_httpd_defaultsite
    Function: cmd.run
        Name: /usr/sbin/a2ensite $(hostname)-example.conf
      Result: False
     Comment: One or more requisite failed: apache_virtualhost_example.copy_httpd_defaultsite, apache_virtualhost_example.change_defaultsite_root
     Changes:   
----------
          ID: add_virtualhost_string
    Function: cmd.run
        Name: /bin/echo "127.0.0.1 $(hostname).example.com" > /etc/hosts
      Result: False
     Comment: One or more requisite failed: apache_virtualhost_example.enable_httpd_defaultsite
     Changes:   
----------
          ID: add_defaultsite_indexfile
    Function: cmd.run
        Name: [ ! -f /var/www/html/$(hostname)/index.html ] && /bin/echo "This is default HTML template for $(hostname) ($(hostname).example.com), created on $(date \"+%d-%m-%Y at %X\")" > /var/www/html/$(hostname)/index.html
      Result: False
     Comment: One or more requisite failed: apache_virtualhost_example.add_virtualhost_string, apache_virtualhost_example.enable_httpd_defaultsite
     Changes:   
----------
          ID: restart_httpd_service
    Function: service.running
        Name: apache2.service
      Result: False
     Comment: One or more requisite failed: apache_virtualhost_example.add_defaultsite_indexfile, apache_virtualhost_example.enable_httpd_defaultsite
     Changes:   

Summary for orjakone
------------
Succeeded: 2 (changed=2)
Failed:    7
------------
Total states run:     9
Total run time: 367.875 ms
```

Hups! Epäonnistumisia, emämunaus. Ihan odotettua, sillä...

...epäonnistumiset johtuvat siitä, että olen määritellyt tietyt ID:t, kuten tässä tapauksessa ehkä kriittisimpänä copy_httpd_defaultsite:n, palauttamaan komennon suorittamisesta arvon false, mikäli mm. tiedosto $(hostname)-example.conf on jo olemassa. Koska kyseinen ID on riippuvuutena alemmille ID:ille, ja nämä ID:t edelleen riippuvuutena eteenpäin muille ID:lle, syntyy ketjureaktio, jossa epäonnistuneita tiloja tulee suuri määrä. Tässä tapauksessa 7 kpl. Tulos oli odotettu _tässä konfiguraatiossa_.

Orjakoneen selainnäkymässä (*xdg-open http://$(hostname).example.com*) ajettuna lopputulos näyttää tältä:

![minion-virtualhost](https://raw.githubusercontent.com/Fincer/central-management-of-multiple-servers/master/images/minion-example.png)

e) Tee tila, joka laittaa esimerkkikotisivun uusille käyttäjille. Voit laittaa esimerkkikotisivu /etc/skel/:iin, niin se tulee automaattisesti ‘adduser tero’ komennolla käyttäjiä luodessa.
--------------

**Vastaus:**

**HUOM!** Tämä on osittain tehtynä jo vastauksissa b) ja c) (Mitä on tehty: On luotu jokaiselle käyttäjälle index.html (b) ja PHP:n kytkemisen yhteydessä index.php (c))

**HUOM!** Tässä olisi voinut hyödyntää esim. kansiorakennetta _/srv/salt/apache_, jonne laitettu state-tiedostot. Nyt toimitaan vielä yksinkertaisemmalla pohjalla, minkä takia state-tiedostoissa esiintyy päällekkäisyyttä. Monimutkaisemmissa konfiguraatioissa puu-rakennetta olisi hyvä harkita (mandatory?).

Lisätään state *2_apache_skelsite.sls*, joka lisää esimerkkikotisivun määriteltyjen minion-koneiden hakemistoon _/etc/skel_ (teemme alihakemiston *public_html* tänne state-tiedostossa...):

```
# Author: Pekka Helenius (~Fincer), 2018

#########################################
# Install Apache HTTP daemon to minions

install_httpd_daemon:
  pkg.installed:
    - pkgs:
      - apache2

#########################################
# Enable Apache userdir module

httpd_userdir:
  cmd.run:
    - name: /usr/sbin/a2enmod userdir
    - require:
      - pkg: install_httpd_daemon

#########################################
# Replace default index.html content

httpd_foo-index:
  cmd.run:
    - name: /bin/echo "foo" > /var/www/html/index.html
    - require:
      - cmd: httpd_userdir
      - pkg: install_httpd_daemon

#########################################
# Restart Apache HTTP daemon

httpd_service_restart_skelsite:
  service.running:
    - name: apache2.service
    - watch:
      - cmd: httpd_userdir

#########################################
# Create /etc/skel/public_html
apache_add_skel_html_dir:
  cmd.run:
    - name: /bin/mkdir -p /etc/skel/public_html
    - require:
      - service: httpd_service_restart_skelsite

#########################################
# Add index.html
apache_default_userindex_file:
  cmd.run:
    - name: /bin/echo "Empty HTML template" > /etc/skel/public_html/index.html
    - require:
       - cmd: apache_add_skel_html_dir

```

Master-koneen output:

```
[10/04/2018 01:15:01 - fincer: ~ ]$ sudo salt 'orjakone' state.apply 2_apache_skelsite
orjakone:
----------
          ID: install_httpd_daemon
    Function: pkg.installed
      Result: True
     Comment: All specified packages are already installed
     Started: 03:46:46.743389
    Duration: 368.537 ms
     Changes:   
----------
          ID: httpd_userdir
    Function: cmd.run
        Name: /usr/sbin/a2enmod userdir
      Result: True
     Comment: Command "/usr/sbin/a2enmod userdir" run
     Started: 03:46:47.113788
    Duration: 21.611 ms
     Changes:   
              ----------
              pid:
                  21155
              retcode:
                  0
              stderr:
              stdout:
                  Module userdir already enabled
----------
          ID: httpd_foo-index
    Function: cmd.run
        Name: /bin/echo "foo" > /var/www/html/index.html
      Result: True
     Comment: Command "/bin/echo "foo" > /var/www/html/index.html" run
     Started: 03:46:47.135793
    Duration: 4.274 ms
     Changes:   
              ----------
              pid:
                  21160
              retcode:
                  0
              stderr:
              stdout:
----------
          ID: httpd_service_restart_skelsite
    Function: service.running
        Name: apache2.service
      Result: True
     Comment: Service restarted
     Started: 03:46:47.161935
    Duration: 103.555 ms
     Changes:   
              ----------
              apache2.service:
                  True
----------
          ID: apache_add_skel_html_dir
    Function: cmd.run
        Name: /bin/mkdir -p /etc/skel/public_html
      Result: True
     Comment: Command "/bin/mkdir -p /etc/skel/public_html" run
     Started: 03:46:47.265901
    Duration: 73.066 ms
     Changes:   
              ----------
              pid:
                  21178
              retcode:
                  0
              stderr:
              stdout:
----------
          ID: apache_default_userindex_file
    Function: cmd.run
        Name: /bin/echo "Empty HTML template" > /etc/skel/public_html/index.html
      Result: True
     Comment: Command "/bin/echo "Empty HTML template" > /etc/skel/public_html/index.html" run
     Started: 03:46:47.341257
    Duration: 13.803 ms
     Changes:   
              ----------
              pid:
                  21185
              retcode:
                  0
              stderr:
              stdout:

Summary for orjakone
------------
Succeeded: 6 (changed=5)
Failed:    0
------------
Total states run:     6
Total run time: 584.846 ms
```

Minion-koneelta tarkistusta (master-koneella katsottuna):

```
[10/04/2018 02:54:51 - fincer: ~ ]$ sudo salt 'orjakone' cmd.run '/bin/ls /etc/skel && [ -d /etc/skel/public_html ] && /bin/cat /etc/skel/public_html/*'
orjakone:
    index.html
    public_html
    Empty HTML template
```

f) Eri asetukset. Tee Package-File-Service tilalla eri asetuksia kuin ne, mitä tehtiin tunnilla; ja eri kuin mitä teit/teet h2 muissa kohdissa. Voit muuttaa jotain toista asetusta samoista demoneista tai valita kokonaan eri demonit.
--------------

**Vastaus:**

Toteutetaan Knock daemonin (knockd - small port-knock daemon) -asennus.

Luodaan master-koneelle tiedosto */srv/salt/knockd.conf*, joka annetaan valituille minioneille (asennetaan polkuun */etc/knockd.conf*)

Haluttu *knockd.conf*:n sisältö (_/srv/salt/knockd.conf_):

```
[options]
    UseSyslog

[openSSH]
    sequence    = tcp:7065,udp:2431,tcp:421,tcp:4113
    seq_timeout = 5
    command     = /sbin/iptables -A INPUT -s %IP% -p tcp --dport 22 -j ACCEPT
    tcpflags    = syn

[closeSSH]
    sequence    = tcp:4113,tcp:421,udp:2431,tcp:7065
    seq_timeout = 5
    command     = /sbin/iptables -D INPUT -s %IP% -p tcp --dport 22 -j ACCEPT
    tcpflags    = syn

```

Luodaan master-koneelle state-tiedosto _/srv/salt/install_knockd.sls_:

```
# Author: Pekka Helenius (~Fincer), 2018

#########################################
# Install Knock daemon to minions

check_ssh:
  pkg.installed:
    - pkgs:
      - ssh

install_knockd:
  pkg.installed:
    - pkgs:
      - knockd

# Deliver Knock daemon configuration file to minions
deliver_knockd-conf:
  file.managed:
    - name: /etc/knockd.conf
    - user: root
    - group: root
    - mode: 644
    - source: salt://knockd.conf
    - require:
      - pkg: install_knockd

# Do not proceed if any SSH sessions are open in minion's side. This is just to avoid any harmful effects
prevent_if_ssh_sessions_open:
  cmd.run:
  - name: 'if [ $(/bin/netstat -tnpa | grep "ESTABLISHED.*sshd" | wc -l) -gt 0 ]; then false; fi'
  - require:
    - pkg: check_ssh

# PROCEED ONLY IF NO SSH SESSIONS ARE OPEN
#
# Drop SSH port connections. Use port which is defined in minion's /etc/ssh/sshd_config file
drop_ssh_port:
  cmd.run:
  - name: /sbin/iptables -A INPUT -p tcp --dport $(grep -E ^[#P]+ort /etc/ssh/sshd_config | awk '{print $2}') -j DROP
  - require:
    - cmd: prevent_if_ssh_sessions_open
    - pkg: check_ssh
    - file: deliver_knockd-conf

# Change default SSH port 22 in minion's /etc/knockd.conf file:
post-configure_knockd-conf:
  cmd.run:
  - name: /bin/sed -i "s/dport 22/dport $(grep -E ^[#P]+ort /etc/ssh/sshd_config | awk '{print $2}')/" /etc/knockd.conf
  - require:
    - pkg: check_ssh
    - file: deliver_knockd-conf

# Enable knockd daemon
enable_knockd_service:
  cmd.run:
    - name: /bin/systemctl enable knockd.service
    - require:
      - pkg: install_knockd

# Restart knockd daemon
restart_knockd_service:
  service.running:
    - name: knockd.service
    - watch:
      - cmd: post-configure_knockd-conf
```

Esimerkki-output master-koneella ajettuna:

```
[10/04/2018 06:17:11 - fincer: ~ ]$ sudo salt 'orjakone' state.apply install_knockd
orjakone:
----------
          ID: check_ssh
    Function: pkg.installed
      Result: True
     Comment: All specified packages are already installed
     Started: 06:25:12.849731
    Duration: 366.695 ms
     Changes:   
----------
          ID: install_knockd
    Function: pkg.installed
      Result: True
     Comment: The following packages were installed/updated: knockd
     Started: 06:25:13.216541
    Duration: 53498.645 ms
     Changes:   
              ----------
              knockd:
                  ----------
                  new:
                      0.7-1ubuntu1
                  old:
----------
          ID: deliver_knockd-conf
    Function: file.managed
        Name: /etc/knockd.conf
      Result: True
     Comment: File /etc/knockd.conf updated
     Started: 06:26:06.717147
    Duration: 17.544 ms
     Changes:   
              ----------
              diff:
                  --- 
                  +++ 
                  @@ -1,15 +1,14 @@
                   [options]
                  -	UseSyslog
                  +    UseSyslog
                   
                   [openSSH]
                  -	sequence    = 7000,8000,9000
                  -	seq_timeout = 5
                  -	command     = /sbin/iptables -A INPUT -s %IP% -p tcp --dport 22 -j ACCEPT
                  -	tcpflags    = syn
                  +    sequence    = tcp:7065,udp:2431,tcp:421,tcp:4113
                  +    seq_timeout = 5
                  +    command     = /sbin/iptables -A INPUT -s %IP% -p tcp --dport 22 -j ACCEPT
                  +    tcpflags    = syn
                   
                   [closeSSH]
                  -	sequence    = 9000,8000,7000
                  -	seq_timeout = 5
                  -	command     = /sbin/iptables -D INPUT -s %IP% -p tcp --dport 22 -j ACCEPT
                  -	tcpflags    = syn
                  -
                  +    sequence    = tcp:4113,tcp:421,udp:2431,tcp:7065
                  +    seq_timeout = 5
                  +    command     = /sbin/iptables -D INPUT -s %IP% -p tcp --dport 22 -j ACCEPT
                  +    tcpflags    = syn
----------
          ID: prevent_if_ssh_sessions_open
    Function: cmd.run
        Name: if [ $(/bin/netstat -tnpa | grep "ESTABLISHED.*sshd" | wc -l) -gt 0 ]; then false; fi
      Result: True
     Comment: Command "if [ $(/bin/netstat -tnpa | grep "ESTABLISHED.*sshd" | wc -l) -gt 0 ]; then false; fi" run
     Started: 06:26:06.735404
    Duration: 59.527 ms
     Changes:   
              ----------
              pid:
                  23916
              retcode:
                  0
              stderr:
              stdout:
----------
          ID: drop_ssh_port
    Function: cmd.run
        Name: /sbin/iptables -A INPUT -p tcp --dport $(grep -E ^[#P]+ort /etc/ssh/sshd_config | awk '{print $2}') -j DROP
      Result: True
     Comment: Command "/sbin/iptables -A INPUT -p tcp --dport $(grep -E ^[#P]+ort /etc/ssh/sshd_config | awk '{print $2}') -j DROP" run
     Started: 06:26:06.795619
    Duration: 457.367 ms
     Changes:   
              ----------
              pid:
                  23927
              retcode:
                  0
              stderr:
              stdout:
----------
          ID: post-configure_knockd-conf
    Function: cmd.run
        Name: /bin/sed -i "s/dport 22/dport $(grep -E ^[#P]+ort /etc/ssh/sshd_config | awk '{print $2}')/" /etc/knockd.conf
      Result: True
     Comment: Command "/bin/sed -i "s/dport 22/dport $(grep -E ^[#P]+ort /etc/ssh/sshd_config | awk '{print $2}')/" /etc/knockd.conf" run
     Started: 06:26:07.253529
    Duration: 16.545 ms
     Changes:   
              ----------
              pid:
                  23963
              retcode:
                  0
              stderr:
              stdout:
----------
          ID: enable_knockd_service
    Function: cmd.run
        Name: /bin/systemctl enable knockd.service
      Result: True
     Comment: Command "/bin/systemctl enable knockd.service" run
     Started: 06:26:07.270551
    Duration: 539.568 ms
     Changes:   
              ----------
              pid:
                  23968
              retcode:
                  0
              stderr:
              stdout:
----------
          ID: restart_knockd_service
    Function: service.running
        Name: knockd.service
      Result: True
     Comment: Started Service knockd.service
     Started: 06:26:08.461999
    Duration: 168.812 ms
     Changes:   
              ----------
              knockd.service:
                  True

Summary for orjakone
------------
Succeeded: 8 (changed=7)
Failed:    0
------------
Total states run:     8
Total run time:  55.125 s
```

Esimerkkikuva minion-koneen Knock daemonin konfiguraatiotiedostosta, jossa on vaihdettu porttinumero sen mukaan kuin se on määritelty minion-koneen SSH-asetuksissa:

![minion-knockd-sample](https://raw.githubusercontent.com/Fincer/central-management-of-multiple-servers/master/images/minion-knockd-example.png)
