mysql op Ubuntu 16.04

Groot was de (mijn) consternatie toen ik probeerde om op een blauwe maandag (het zal eerder een zaterdag geweest zijn, maar goed) een database aan te maken voor één of ander project. Normaal is dat niet zo moeilijk: inloggen als root, database aanmaken et voilà, Bob’s your uncle!

Maar niet dus. Hoewel ik het mij niet kon herinneren, bleek de mysql server al geïnstalleerd te zijn en, nog vreemder, er was een rootwachtwoord ingesteld. Nu ben ik, als goede systeembeheerder, nogal paranoïde, en was het dus niet onmogelijk dat ik in het verleden het wachtwoord toch had ingesteld.

Maar een goede systeembeheerder documenteert, en het ingestelde wachtwoord kwam niet overeen met het door mij gedocumenteerde mysqlwachtwoord (ik gebruik Keepassxc als wachtwoordbeheerder). Allemaal wreed vreemd.

Een mysqlwachtwoord opnieuw instellen is niet zo moeilijk, in principe, maar in dit geval wou het maar niet werken. Na een lange avond zoeken (u wil het echt niet weten), bleek deze lijn in /var/log/syslog (en niet in /var/log/mysql/error.log trouwens) het antwoord te bevatten:

[Warning] 'user' entry 'root@localhost' has both a password and an authentication plugin specified. The password will be ignored.

Tussen Ubuntu 14.04 (mijn vorige versie) en Ubuntu 16.04 (de huidige) is de standaardauthenticatieplugin van MariaDB op Ubuntu veranderd naar unix_socket. En daarom lukte het niet om het wachtwoord te wijzigen, of in te loggen met het nieuwe wachtwoord.

Om alsnog toegang te krijgen tot de server, moet u simpelweg als root (de Linuxgebruiker, niet de mysqlgebruiker) mysql -u root uitvoeren:

sudo mysql -u root

Je kan, en ik citeer, niet meer inloggen als een andere gebruiker wanneer die plugin geactiveerd is voor een bepaalde gebruiker; dus enkel root kan inloggen als root.

U moet het maar weten. Of de release notes lezen natuurlijk …

SSH SOCKS-tunnel en Firefox

Ik heb een VPN. Maar dat is eigenlijk een management-VPN die bedoeld is om servers te beheren, en niet echt om internetverkeer te verwerken om spionerende netwerkbeheerders te slim af te zijn.

Dus, een andere oplossing. Een simpele oplossing.

Met SSH, en de jump host uit dit bericht is het zelfs heel simpel. SSH kan immers zonder al te veel moeite een SOCKS-tunnel opzetten, waarmee je al het verkeer dat naar de getunnelde poort gestuurd wordt kan doorsturen naar de remote host.

Het SSH-commando is simpel, de uitleg iets minder.

ssh -D 9999 -C -q -N pieter@vpn.helptux.be

Dit commando doet het volgende:

  • -D 9999: forward poort 9999 op jouw lokaal systeem naar vpn.helptux.be
  • -C: comprimeer het verkeer
  • -q: geen output
  • -N: er volgt geen commando (houdt de tunnel open)

Je maakt hiermee automatisch een SOCKS-tunnel aan die al het verkeer dat je naar poort 9999 stuurt zal forwarden naar vpn.helptux.be, waar het verkeer dan verder via het juiste protocol (bv. HTTP) wordt verwerkt.

Je kan dan in jouw browser als SOCKS-proxy (niet als HTTP(S)-proxy, dit zal niet werken) 127.0.0.1:9999 ingeven. Stuur al het verkeer (ook DNS) via de proxy, maar laat de instellingen voor de HTTP, HTTPS en FTP(S)-proxies leeg. SOCKS zal dit automatisch oplossen.

SSH Jump host

Als je meerdere servers hebt, dan is het aangeraden om een intern, management-only, netwerk te voorzien, om beheertaken (DNS, Puppet, Zabbix enz.) uit te voeren die je niet via het publieke netwerk wil sturen. Uiteraard heeft dit netwerk geen toegang tot het internet. Gezien mijn hosts niet allemaal in hetzelfde datacenter zitten, en ik geen geld heb voor een dedicated link, gebruik ik OpenVPN voor het achterliggende netwerk.

Nu wil ik wel kunnen inloggen op alle hosts via dit netwerk, voornamelijk omdat ik dan de interne domeinnamen kan gebruiken. Maar daarvoor heb je natuurlijk een toegang nodig, de jump host. Voor mij is dat de VPN-server (bereikbaar via SSH vanop het publieke netwerk).

Uiteraard ondersteunt SSH dit, en het is zelfs niet zo moeilijk.

Zeg dat alle hosts zich in het interne *.dc.helptux.be-domein bevinden, en dat pieter de gebruiker is om aan te loggen. vpn.helptux.be is de domeinnaam van de VPN-server (dit werkt ook met IP-adressen).

Voeg dan het volgende toe in $home/.ssh/config:

Host *.dc.helptux.be
 ProxyJump vpn.helptux.be

Omdat SSH eerst inlogt op de jump host kan je de hostnamen van het interne netwerk en de interne DNS-server gebruiken, zolang de jump host de domeinnamen kan resolven natuurlijk.

Als jouw lokale gebruiker niet gelijk is aan de gebruiker op de jump host, voeg dan je gebruikersnaam toe aan de jump host:

ProxyJump pieter@vpn.helptux.be

Uiteraard kan je ook User en IdentityFile toevoegen, maar let wel dat IdentityFile de locatie is op jouw lokaal systeem (bv. laptop) en niet op de jump host. User is de gebruiker waarmee je inlogt op de uiteindelijke host, niet de jump host.

Voor gebruikers van een OpenSSH-versie onder 7.3 werkt het bovenstaande, mooie commando niet. Maar, niet getreurd, ook voor hen is er hulp! In plaats van ProxyJump user@jumphost moet je het volgende in $home/.ssh/config plaatsen:

ProxyCommand ssh pieter@vpn.helptux.be -W %h:%p

Nu werkt het ook op Ubuntu …

SELinux en poorten

Om een proces (bv. httpd) toegang te geven tot een bepaalde poort moet je in SELinux de context van de poort veranderen.

Dat is niet zo moeilijk:

semanage port -a -t http_port_t -p tcp 8443

Maar, soms is de poort al toegewezen aan een context en krijg je een toffe foutmelding:

Port tcp/8443 already defined

Maar, je kan gelukkig ook, in plaats van een combinatie toe te voegen (-a), ook de bestaande combinatie wijzigen (-m):

semanage port -m -t http_port_t -p tcp 8443

(Het staat ook in de man-page.)

En zo is SELinux gelukkig, en is iedereen gelukkig!

hiera-eyaml – caveat emptor

Ik gebruik Puppet voor mijn persoonlijk serverpark, en ben daar best tevreden over. Maar af en toe …

Zoals nu dus. In het kader van een herstructurering wordt de Puppetmaster gemigreerd van een VPS naar een fysieke server. Wanneer ik zeg gemigreerd, bedoel ik eigenlijk opnieuw opgezet, met een aantal verbeteringen, zoals daar zijn verschillende environments en r10k voor de synchronisatie van repositories en modules.

Omdat alles in git zit (uiteraard) en ik een beetje paranoïde ben, versleutel ik mijn wachtwoorden en SSH-sleutels (opgeslagen in Hiera) met hiera-eyaml.

De gem (Ruby …) was mooi geïnstalleerd, en mijn hiera.yaml (geconfigureerd per environment) leek in orde.

:hierarchy:
 - "%{::osfamily}"
 - webservers
 - databases
 - roles
 - common
:backends:
 - eyaml
 - yaml
:yaml:
 :datadir: "/etc/puppetlabs/code/environments/%{::environment}/hieradata"
:eyaml:
 :datadir: "/etc/puppetlabs/code/environments/%{::environment}/hieradata"
 :pkcs7_private_key: "/etc/puppetlabs/puppet/keys/private_key.pkcs7.pem"
 :pkcs7_public_key: "/etc/puppetlabs/puppet/keys/public_key.pkcs7.pem"

Maar … Het werkte toch niet (anders was er nu geen blogpost). Na een (vruchteloze) speurtocht doorheen /etc om alle mogelijke hiera.yaml-bestanden die de Puppetserver (foutief) zou kunnen inladen te verwijderen, bleef dezelfde foutmelding terugkomen.

Sep 1 21:14:40 stock puppet-agent[6330]: Could not retrieve catalog from remote server: Error 500 on SERVER: Server Error: Function lookup() did not find a value for the name 'account_data' on node s1.admin.dc.nidavellir.be

Maar dan, in de krochten van de README (…), bleek dat het niet voldoende was om de gem te installeren via gem install hiera-eyaml. Neen. Dat moest gebeuren via de Puppetserver:

/opt/puppetlabs/bin/puppetserver gem install hiera-eyaml

En jawel …

Sep 2 12:32:53 stock puppet-agent[23914]: Applied catalog in 152.87 seconds

Hoera!

Kerberos: een tragikomedie

Prelude: Vandaag een update uitgevoerd van Fedora 25 naar Fedora 26, en alles ging goed. Alles? Neen, niet alles. Kerberos bleef weerstand bieden aan de overweldigers. Alles is geconfigureerd om via Kerberos en SSH passwordless te kunnen inloggen op het serverpark, maar SSH weigerde koppig dienst.

Confrontatie: De eerste foutmelding leek te wijzen naar het ontbreken van /etc/krb5.keytab (Server not found in Kerberos database). En inderdaad, het vermaledijde bestand was niet aanwezig. Helaas is het niet zo eenvoudig (“onmogelijk”) om te vinden hoe je dat bestand moet aanmaken. Wel wat er moet instaan, maar niet hoe je het moet maken. Ik bespaar u de details, als het /etc/krb5.conf-bestand hetzelfde is als toen het nog werkte, dan moet het zo (ktutil: moet je niet overtypen):

ktutil
ktutil: addent -password -p pieter@dc.helptux.be -k 1 -e RC4-HMAC
ktutil: wkt /etc/krb5.keytab
ktutil: q

kinit pieter@dc.helptux.be

Catharsis: En toch bleef het probleem bestaan. De ontbrekende keytab was dus niet het probleem. Na het raadplegen van een orakel bleek het probleem, zoals altijd, DNS. Ik gebruik korte hostnames om in te loggen (i.e. web1 ipv. web1.dc.helptux.be), maar Kerberos verwacht lange hostnames. Je kan dat oplossen door altijd ssh web1.dc.helptux.be te gebruiken, maar dat was vroeger niet nodig, en dus gaan we dat ook nu niet zo doen. Gelukkig is er in /etc/krb5.conf een instelling die het probleem oplost: dns_canonicalize_hostname. Dit staat standaard op true, maar om onbekende redenen stond het op false. Een kleine aanpassing later werkte alles terug. Zeus zij geprezen!

dns_canonicalize_hostname = true

Puppet: invalid byte sequence in US-ASCII

Puppet probeert een bestand te parsen, denkt dat het ASCII is, maar dat is het niet en faalt dus. Een é gebruiken doe je niet ongestraft.

Dit is geen probleem met Puppet, maar met de locale die ingesteld staat op het systeem. Op zich eenvoudig op te lossen, ware het niet dat het “systeem” in kwestie een docker container is, gebaseerd op Red Hat Enterprise Linux 7.3.

Om een lang verhaal kort te maken, je moet in de Dockerfile de locale-environment variables toevoegen (het uitvoeren van localegen is op RHEL 7.3 niet nodig).

ENV LANG en_US.UTF-8
ENV LC_ALL en_US.UTF-8
ENV LANGUAGE en_US:en

En zo staat de locale ingesteld op UTF-8, waardoor de puppet parser dit overneemt en de foutmelding magisch verdwijnt.

Hoera!

NT_STATUS_NO_SUCH_GROUP

De foutmelding NT_STATUS_NO_SUCH_GROUP uit Samba betekent dat één van de groepen die je gebruikt bij de share die je probeert te mounten niet bestaat.

Dat kan er één zijn uit valid users, write list, maar ook force group.

En uiteraard was ik die laatste vergeten. Dag voormiddag!

RPM’s van Python-libraries

Het is niet zo moeilijk als het lijkt. Tenminste, wanneer je setup.py gebruikt, wat de nieuwe (Python 2.7+, dus niet meer zo nieuw) manier is om Pythonpackages te maken. setup.py bevat een call naar de setup-functie, wat een deel is van setuptools.

Hoe je zo’n functie opbouwt kan je in de documentatie vinden, of in de fantastische Python packaging tutorial. Met setup.py kan je de package installeren, maar om te delen met vrienden (die toevallig een RPM-distro gebruiken), kan je ook een echte OS-package maken.

python setup.py bdist_rpm

Je kan eventueel nog extra opties toevoegen, zoals dependencies (–requires) of een specifieke release tag (de RPM-versie, bv. -1) (–release). Zo wordt het heel simpel om een repository op te bouwen van extra, custom, libraries die je zelf hebt gefabriceerd en gebruikt voor jouw projecten. Ook applicaties kan je zo verspreiden.