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