Puppetmodules in RubyMine

In RubyMine, een uitstekende IDE uit de Jetbrainsstal, kan je Puppetmodules ontwikkelen (de taal is ondersteund), maar je moet enkele dingen in het achterhoofd houden.

Zo eentje heb ik vandaag ontdekt. Opdat RubyMine automatisch de naam van variabelen, functies en klassen uit jouw module zou aanvullen, moet je ervoor zorgen dat ze op één of andere manier door heeft dat je een module aan het ontwikkelen bent.

De oplossing is eenvoudig en elegant: voeg een metadata.json-bestand toe en zorg ervoor dat de structuur van de module overeen komt met de documentatie.

Een kleine moeite, een wereld van verschil.

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 …

WSGIPassAuthorization

Een RESTful API die niet helemaal publiek mag zijn is meestal beveiligd met een variant van HTTP Basic Authentication. Daar is natuurlijk niets mis mee, want het is veruit de eenvoudigste manier voor een API-consument om zich te identificeren.

Maar onlangs stootte ik toch op een caveat emptor: wanneer je een API in Python (bv. Flask) via mod_wsgi beschikbaar stelt, dan werkt het plots niet meer om met Basic Authentication aan te melden. Mysterie, mysterie, zeker omdat het in de ontwikkelomgeving wel werkte.

Na lang (~ 1/2e dag) zoeken bleek mod_wsgi de schuldige (en mijn gebrekkige lectuur van de handleiding, want het is gedocumenteerd). In een standaardopstelling worden de authorization headers immers onderschept door Apache, die zelf de authenticatie wil uitvoeren. Uiteraard wist ik dat niet, en had Apache ook niet zo geconfigureerd. En dus stond ik voor het mysterie van de missende header.

Maar via wat google-fu en een blogpost kwam ik dan toch op de oplossing. In de vhost (of elders, al naargelang) waar je de wsgi-applicatie hebt geconfigureerd moet je de instelling WSGIPassAuthorization op On zetten (en dan de webserver herstarten, dat spreekt).

WSGIPassAuthorization On

En hoera! De authenticatie werkt! Op naar het volgende probleem!

Wetteren – Gent-Sint-Pieters: in het zadel!

Ik ben vandaag met de fiets van Wetteren naar het Sint-Pietersstation gereden. Op zich geen wereldschokkend nieuws (al is het een beetje vreemd voor iemand die altijd de trein neemt), maar ik ga het er toch even over hebben. We moeten immers allemaal groen zijn (fiets! openbaar vervoer!), maar wanneer iemand het dan ook echt eens wil doen blijkt dit toch ook weer niet zo eenvoudig …

Er is geen “fietsostrade” van Wetteren naar Gent (wel een autostrade, de E40, een steenweg, de N9, en diverse spoorwegen), dus er is geen mooi recht fietspad. Ik heb dus zelf een beetje een route gefabriceerd, met hopelijk een mooie balans tussen snelheid (de droom om per fiets naar Gent en dan per trein naar Brussel is nog niet dood) en veiligheid (één accident is meer dan genoeg).

“Wetteren – Gent-Sint-Pieters: in het zadel!” verder lezen

Git: terugdraaien naar een specifieke commit

Iets wat heel eenvoudig is. Als je weet hoe.

git reset --soft <commit_hash>

Dit zet alle wijzigingen in jouw lokale kopie terug naar de status van die specifieke commit. Alle latere commits worden hierdoor gewist. Afhankelijk van de instellingen van je remote (bv. Github) kan je dit ook pushen, wat ook daar alle latere commits doet verdwijnen (ze zijn ook niet meer terug te halen!).

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!