Golem

This document describes how to build Golem, a multi-function server. Golem runs on commodity router hardware and provides a number of features:

  • SSH access
  • a media service compatible with iTunes
  • a file share
  • an LDAP and Kerberos service
  • a network proxy
  • a NetFlow collector

We build Golem on top of OpenWrt because of the distribution’s simplicity and small size. Golem is made up of roughly 120 packages, and its programs and configurations take up less than 50 MB of storage space. Here we assume that Golem will run within the confines of a Xen hypervisor.

Establish the Golem VM

Perform the following steps on the Xen Dom0 host to establish the VM which will host Golem:

  1. Obtain the x86_64 OpenWrt image at https://downloads.lede-project.org/releases/17.01.1/targets/x86/64/lede-17.01.1-x86-64-combined-ext4.img.gz.
  2. Uncompress the image and place it at /var/lib/xen/images/golem-lede-17.01.1-x86-64-combined-ext4.img on the Xen Dom0 host.
  3. Create a disk image to serve as the server’s large data store (see our notes on platform virtualization) and name it /var/lib/xen/images/golem-data.qcow.
  4. Write the following at /etc/xen/vm-golem.cfg on the Xen Dom0 host (replace XX:XX:XX:XX:XX:XX):
name    = "golem"
memory  =  1024
vcpus   =  1
builder = "hvm"
vif     = [ "model=e1000,script=vif-bridge,bridge=xenbr0,mac=XX:XX:XX:XX:XX:XX" ]
disk    = [
  "tap2:tapdisk:aio:/var/lib/xen/images/golem-lede-17.01.1-x86-64-combined-ext4.img,xvda,w",
  "tap2:qcow:/var/lib/xen/images/golem-data.qcow,xvdb,w"
          ]
serial  = "pty"

Software installation

Perform the following steps on Golem:

  1. Set the root password: passwd.
  2. Remove unnecessary packages:
opkg remove \
        dnsmasq \
        kmod-ppp \
        kmod-pppoe \
        kmod-pppox \
        kmod-r8169 \
        logd \
        luci \
        luci-app-firewall \
        luci-base \
        luci-lib-ip \
        luci-lib-nixio \
        luci-proto-ipv6 \
        luci-proto-ppp \
        luci-theme-bootstrap \
        mtd \
        odhcpd-ipv6only \
        ppp \
        ppp-mod-pppoe \
        r8169-firmware \
        uhttpd-mod-ubus \
        uhttpd
  1. Configure networking by writing /etc/config/network:
config interface loopback
        option ifname lo
        option proto static
        option ipaddr 127.0.0.1
        option netmask 255.0.0.0

config interface lan
        option ifname eth0
        option proto dhcp
  1. Install the necessary software:
opkg update
opkg install \
        block-mount \
        ca-certificates \
        dmapd \
        freifunk-watchdog \
        gst1-mod-app \
        gst1-mod-audioconvert \
        gst1-mod-audioparsers \
        gst1-mod-flac \
        gst1-mod-gio \
        gst1-mod-id3demux \
        gst1-mod-lame \
        gst1-mod-mpeg2dec \
        gst1-mod-mpg123 \
        gst1-mod-ogg \
        gst1-mod-playback \
        gst1-mod-theora \
        gst1-mod-typefindfunctions \
        gst1-mod-vorbis \
        krb5-server \
        nfdump \
        nfs-kernel-server \
        openldap-server \
        rsync \
        syslog-ng \
        tinyproxy \
        zoneinfo-core \
        zoneinfo-northamerica
  1. Install a public SSH key at /etc/dropbear/authorized_keys.

Configuring Kerberos authentication

  1. /etc/krb5.conf (replace EXAMPLE.COM):
[libdefaults]
        default_realm = EXAMPLE.COM
        dns_lookup_realm = false
        dns_lookup_kdc = false
        ticket_lifetime = 24h
        forwardable = yes

[realms]
        EXAMPLE.COM = {
                kdc = localhost:88
                admin_server = localhost:749
                default_domain = local
        }

[domain_realm]
        .local = EXAMPLE.COM
        local = EXAMPLE.COM
  1. Add Kerberos principals by running kadmin.local and then add_principal user for each user.

Configuring LDAP network information

  1. /etc/openldap/example.com.cert: Place your certificate in /etc/openldap/example.com.cert.

  2. /etc/openldap/example.com.key: Place your private key in /etc/openldap/example.com.key.

  3. /etc/openldap/ca.cert: Place your CA certificate in /etc/openldap/ca.cert.

  4. /etc/openldap/slapd.conf (replace PASSWORD and example.com):

include         /etc/openldap/schema/core.schema
include         /etc/openldap/schema/cosine.schema
include         /etc/openldap/schema/inetorgperson.schema
include         /etc/openldap/schema/nis.schema
include         /etc/openldap/schema/autofs.schema
include         /etc/openldap/schema/sudoers.schema

allow bind_v2

TLSCACertificateFile /etc/openldap/ca.cert
TLSCertificateFile /etc/openldap/example.com.cert
TLSCertificateKeyFile /etc/openldap/example.com.key

pidfile         /var/run/slapd.pid
argsfile        /var/run/slapd.args

database        ldif
directory       /etc/openldap/db
suffix          "dc=example,dc=com"
rootdn          "cn=Manager,dc=example,dc=com"
rootpw          PASSWORD
  1. /etc/openldap/schema/sudoers.schema:
attributetype ( 1.3.6.1.4.1.15953.9.1.1
        NAME 'sudoUser'
        DESC 'User(s) who may  run sudo'
        EQUALITY caseExactIA5Match
        SUBSTR caseExactIA5SubstringsMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )

attributetype ( 1.3.6.1.4.1.15953.9.1.2
        NAME 'sudoHost'
        DESC 'Host(s) who may run sudo'
        EQUALITY caseExactIA5Match
        SUBSTR caseExactIA5SubstringsMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )

attributetype ( 1.3.6.1.4.1.15953.9.1.3
        NAME 'sudoCommand'
        DESC 'Command(s) to be executed by sudo'
        EQUALITY caseExactIA5Match
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )

attributetype ( 1.3.6.1.4.1.15953.9.1.4
        NAME 'sudoRunAs'
        DESC 'User(s) impersonated by sudo'
        EQUALITY caseExactIA5Match
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )

attributetype ( 1.3.6.1.4.1.15953.9.1.5
        NAME 'sudoOption'
        DESC 'Options(s) followed by sudo'
        EQUALITY caseExactIA5Match
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )

attributetype ( 1.3.6.1.4.1.15953.9.1.6
        NAME 'sudoRunAsUser'
        DESC 'User(s) impersonated by sudo'
        EQUALITY caseExactIA5Match
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )

attributetype ( 1.3.6.1.4.1.15953.9.1.7
        NAME 'sudoRunAsGroup'
        DESC 'Group(s) impersonated by sudo'
        EQUALITY caseExactIA5Match
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )

attributetype ( 1.3.6.1.4.1.15953.9.1.8
        NAME 'sudoNotBefore'
        DESC 'Start of time interval for which the entry is valid'
        EQUALITY generalizedTimeMatch
        ORDERING generalizedTimeOrderingMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )

attributetype ( 1.3.6.1.4.1.15953.9.1.9
        NAME 'sudoNotAfter'
        DESC 'End of time interval for which the entry is valid'
        EQUALITY generalizedTimeMatch
        ORDERING generalizedTimeOrderingMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )

attributeTypes ( 1.3.6.1.4.1.15953.9.1.10
        NAME 'sudoOrder'
        DESC 'an integer to order the sudoRole entries'
        EQUALITY integerMatch
        ORDERING integerOrderingMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )

objectclass ( 1.3.6.1.4.1.15953.9.2.1 NAME 'sudoRole' SUP top STRUCTURAL
        DESC 'Sudoer Entries'
        MUST ( cn )
        MAY ( sudoUser $ sudoHost $ sudoCommand $ sudoRunAs $ sudoRunAsUser $
                sudoRunAsGroup $ sudoOption $ sudoNotBefore $ sudoNotAfter $
                sudoOrder $ description )
        )
  1. From a computer with ldapadd on golem’s network, execute ldapadd -x -D "cn=Manager,dc=example,dc=com" -W -f accounts.ldif, where accounts.ldif contains records like (replace example, com, user, and Some User):
dn: dc=example,dc=com
objectClass: organization
objectClass: dcObject
o: Example Organization
dc: example

dn: automountMapName=auto_master,dc=example,dc=com
objectClass: top
objectClass: automountMap
automountMapName: auto_master

dn: automountMapName=auto_root,dc=example,dc=com
objectClass: top
objectClass: automountMap
automountMapName: auto_root

dn: automountKey=/-,automountMapName=auto_master,dc=example,dc=com
objectClass: top
objectClass: automount
automountKey: /-
automountInformation: auto_root

dn: automountKey=/home,automountMapName=auto_root,dc=example,dc=com
objectClass: top
objectClass: automount
automountKey: /home
automountInformation: golem.example.com:/home/

dn: ou=group,dc=example,dc=com
objectClass: organizationalUnit
ou: group

dn: cn=ldapusers,ou=group,dc=example,dc=com
objectClass: posixGroup
objectClass: top
cn: ldapusers
userPassword:: WFhYWA==
gidNumber: 1002

dn: ou=people,dc=example,dc=com
objectClass: organizationalUnit
ou: people

dn: uid=user,ou=people,dc=example,dc=com
uid: user
cn: Some User 
objectClass: account
objectClass: posixAccount
objectClass: top
userPassword:: WFhYWA==
loginShell: /bin/bash
uidNumber: 1102
gidNumber: 1002
homeDirectory: /home/user
gecos: Some User

dn: ou=sudoers,dc=example,dc=com
objectClass: top
objectClass: organizationalUnit
ou: sudoers

dn: cn=user,ou=sudoers,dc=example,dc=com
objectClass: top
objectClass: sudoRole
cn: user
sudoUser: user
sudoHost: ALL
sudoCommand: ALL

Configuring the dmapd media server

  1. /etc/dmapd.conf:
[General]
Database-Dir=/mnt/sda1/var/dmapd

[Music]
Type=DAAP
Dirs=/mnt/sda1/Storage/Music/
Transcode-Mimetype=audio/mp3

[Picture]
Type=DPAP
Dirs=/mnt/sda1/Storage/Pictures/

Configuring NFS

  1. /etc/exports:
/mnt/sda1 *(fsid=root,rw,insecure,no_subtree_check,async)
/mnt/sda1/Storage *(rw,insecure,no_subtree_check,async)
/mnt/sda1/home *(rw,insecure,no_subtree_check,async)

Configuring Tinyproxy

  1. /etc/tinyproxy-filter.conf: List the websites that you want tinyproxy to allow access to, one per line (e.g., www.example.com).

Configure the firewall

  1. /etc/config/firewall:
config defaults
        option drop_invalid 1
        option input ACCEPT
        option output ACCEPT
        option forward ACCEPT

config zone
        option name lan
        option network lan
        option input ACCEPT
        option output ACCEPT
        option forward DROP

Configure basic system settings

  1. /etc/config/fstab:
config global automount
        option from_fstab 1
        option anon_mount 1

config global autoswap
        option from_fstab 1
        option anon_swap  1
  1. /etc/config/nfs:
config nfs nfs
        option minversion '4'
  1. /etc/config/system:
config system
        option hostname golem.example.com
        option timezone EST5EDT,M3.2.0,M11.1.0

config timeserver ntp
        list server     0.openwrt.pool.ntp.org
        list server     1.openwrt.pool.ntp.org
        list server     2.openwrt.pool.ntp.org
        list server     3.openwrt.pool.ntp.org
        option enabled 1
        option enable_server 0
  1. /etc/config/tinyproxy:
config tinyproxy

option enable 1
option User nobody
option Group nogroup
option Port 8080
option Timeout 600
option SysLog 1
option LogLevel Info
option MaxClients 100
option MinSpareServers 1
option MaxSpareServers 3
option StartServers 1
option MaxRequestsPerChild 0
option ViaProxyName "tinyproxy"
option Filter "/etc/tinyproxy-filter.conf"
option FilterDefaultDeny 1
  1. /etc/config/freifunk-watchdog:
config process
        option process dropbear 
        option initscript /etc/init.d/dropbear

config process
        option process crond
        option initscript '/etc/init.d/cron'
        
config process
        option process dmapd
        option initscript /etc/init.d/dmapd     

config process
        option process krb5kdc
        option initscript /etc/init.d/krb5kdc
        
config process
        option process slapd
        option initscript /etc/init.d/ldap
  1. /etc/config/network:
config interface loopback
        option ifname lo
        option proto static
        option ipaddr 127.0.0.1
        option netmask 255.0.0.0

config interface lan
        option ifname eth0
        option proto dhcp
  1. /etc/config/dropbear:
config dropbear
        option PasswordAuth 'off'
        option RootPasswordAuth 'off'
        option Port         '22'
  1. /etc/config/nfcapd:
config nfcapd nfcapd
        option enabled 1
        option port 9995
        option logdir /mnt/sda1/var/log/netflow