Seite wählen

NETWAYS Blog

Zugangsdaten und globale Variablen in Icinga 2

Viele Kunden fragen mich, wie man zentral Zugangsdaten oder allgemeine Variablen in Icinga 2 verwalten kann. Icinga 1.x und Nagios hatte für solche Zwecke die resources.cfg, dort wurden zentrale Macros wie $USER1$ usw. konfiguriert.

Nun hat Icinga 2 einen relativen ähnlichen Mechanismus, mit dem man an einer zentralen Stelle globale Konstanten bzw. Variablen speichern kann. Dann können diese überall in der Konfiguration benutzt werden. Aber leider nicht als Macro, was die Verwendung mit dem Director etwas schwieriger macht.

Aber dafür gibt es Abhilfe, auch dafür pflegen wir die Werte in der /etc/icinga2/constants.conf

const GlobalVars = {
  OracleDbUser = "svcicinga"
  OracleDbPassword = "hunter2"
}

Nun fehlt noch eine kleine Konfiguration, damit diese Variablen auch überall verfügbar sind, dazu bearbeiten wir die Datei /etc/icinga2/conf.d/app.conf und die IcingaApplication.

object IcingaApplication "app" {
  vars = GlobalVars
}

Jetzt sind die Variablen überall auch als Macro verfügbar.

vars.oracle_health_username = "$OracleDbUser$"
vars.oracle_health_password = "$OracleDbPassword$"

Ich wünsche viel Spaß beim Ausprobieren, und hoffentlich ruhige Feiertage und einen guten Rutsch ins Jahr 2020!

Bildrechte: Wikimedia Commons – von Psyomjesus

The Icinga Config Compiler: An Overview

The Icinga configuration format was designed to be easy to use for novice users while at the same time providing more advanced features to expert users. At first glance it might look like a simple key-value configuration format:

object Host "example.icinga.com" {
	import "generic-host"
	address = "203.0.113.17"
	address6 = "2001:db8::17"
}

However, it features quite a bit of functionality that elevates it to the level of scripting languages: variables, functions, control flow (if, for, while) and a whole lot more.

Icinga’s scripting language is used in several places:

  • configuration files
  • API filter expressions
  • auto-generated files used for keeping track of modified attributes

In this post I’d like to show how some of the config machinery works internally.

The vast majority of the config compiler is contained in the lib/config directory. It weighs in at about 4.5% of the entire code base (3059 out of 68851 lines of code as of July 2018). The compiler is made up of three major parts:

Lexer

The lexer (lib/config/config_lexer.ll, based on flex) takes the configuration source code in text form and breaks it up into tokens. In doing so the lexer recognizes all the basic building blocks that make up the language:

  • keywords (e.g. „object“, „for“, „break“) and operators (e.g. >, ==, in)
  • identifiers
  • literals (numbers, strings, booleans)
  • comments

However, it has no understanding of how these tokens fit together syntactically. For that it forwards them to the parser. All in all the lexer is actually quite boring.

Parser/AST

The parser (lib/config/config_parser.yy, based on GNU Bison) takes the tokens from the lexer and tries to figure out whether they represent a valid program. In order to do so it has production rules which define the language’s syntax. As an example here’s one of those rules for „for“ loops:

| T_FOR '(' identifier T_FOLLOWS identifier T_IN rterm ')'
{
        BeginFlowControlBlock(context, FlowControlContinue | FlowControlBreak, true);
}
rterm_scope_require_side_effect
{
        EndFlowControlBlock(context);
        $$ = new ForExpression(*$3, *$5, std::unique_ptr($7), std::unique_ptr($10), @$);
        delete $3;
        delete $5;
}

Here’s a list of some of the terms used in the production rule example:

Symbol Description
T_FOR Literal text „for“.
identifier A valid identifier
T_FOLLOWS Literal text „=>“.
T_IN Literal text „in“.
BeginFlowControlBlock, EndFlowControlBlock These functions enable the use of certain flow control statements which would otherwise not be allowed in code blocks. In this case the „continue“ and „break“ keywords can be used in the loop’s body.
rterm_scope_require_side_effect A code block for which Icinga can’t prove that the last statement doesn’t modify the program state.
An example for a side-effect-free code block would be { 3 } because Icinga can prove that executing its last statement has no effect.

After matching the lexer tokens against its production rules the parser continues by constructing an abstract syntax tree (AST). The AST is an executable representation of the script’s code. Each node in the tree corresponds to an operation which Icinga can perform (e.g. „multiply two numbers“, „create an object“, „retrieve a variable’s value“). Here’s an example of an AST for the expression „2 + 3 * 5“:

Note how the parser supports operator precedence by placing the AddExpression AST node on top of the MultiplyExpression node.

Icinga’s AST supports a total of 52 different AST node types. Here are some of the more interesting ones:

Node Type Description
ArrayExpression An array definition, e.g. [ varName, "3", true ]. Its interior values are also AST nodes.
BreakpointExpression Spawns the script debugger console if Icinga is started with the -X command-line option.
ImportExpression Corresponds to the import keyword which can be used to import another object or template.
LogicalOrExpression Implements the || operator. This is one of the AST node types which don’t necessarily evaluate all of its interior AST nodes, e.g. for true || func() the function call never happens.
SetExpression This is essentially the = operator in its various forms, e.g. host_name = "localhost"

On their own the AST nodes just describe the semantical structure of the script. They don’t actually do anything in terms of performing any real actions.

VM

Icinga contains a virtual machine (in the language sense) for executing AST expressions (mostly lib/config/expression.cpp and lib/config/vmops.hpp). Given a reference to an AST node – such as root node from the example in the previous section – it attempts to evaluate that node. What that means exactly depends on the kind of AST node:

The LiteralExpression class represents bare values (e.g. strings, numbers and boolean literals). Evaluating a LiteralExpression AST node merely yields the value that is stored inside of that node, i.e. no calculation of any kind takes place. On the other hand, the AddExpression and MultiplyExpression AST nodes each have references to two other AST nodes. These are the operands which are used when asking an AddExpression or MultiplyExpression AST node for „their“ value.

Some AST nodes require additional context in order to run. For example a script function needs a way to access its arguments. The VM provides these – and a way to store local variables for the duration of the script’s execution – through an instance of the StackFrame (lib/base/scriptframe.hpp) class.

Future Considerations

All in all the Icinga scripting language is actually fairly simple – at least when compared to other more sophisticated scripting engines like V8. In particular Icinga does not implement any kind of optimization.
A first step would be to get rid of the AST and implement a bytecode interpreter. This would most likely result in a significant performance boost – because it allows us to use the CPU cache much more effectively than with thousands, if not hundreds of thousands AST nodes scattered around the address space. It would also decrease memory usage both directly and indirectly by avoiding memory fragmentation.
However, for now the config compiler seems to be doing its job just fine and is probably one of the most solid parts of the Icinga codebase.

SSL leicht gemacht – forcierte Weiterleitung von HTTP auf HTTPS einrichten


In den vorherigen Teilen der Serie wurde bereits die Erstellung und Einbindung der Zertifikate beschrieben. Eines Tages wünscht sich der Admin jedoch die sichere Verbindung aller Seitenbesucher, ohne dass diese manuell ein https voranstellen müssen. Gerade bei einer Migration einer bestehenden Seite wird der
Parallelbetrieb erst nach eingehenden Tests eingestellt und das SSL jeweils forciert, um Seitenbesucher nicht mit ungültigen Zertifikaten oder Mixed Content zu verunsichern.
Die eigentliche Umsetzung ist dann relativ einfach und wird in unserem Beispiel direkt in der Vhost-Definition des Apache vorgenommen. Übrigens, die verfügbaren Vhosts sind zu finden unter: /etc/apache2/sites-available. Hier wird nun der HTTP-Vhost (Port 80) um den unten aufgezeigten Block mit den Rewrites erweitert.

<VirtualHost *:80>
  ServerAdmin webmaster@netways.de
  ServerName www.netways.de
  DocumentRoot /var/www/html/netways.de/
  <Directory /var/www/html/netways.de/>
   Options FollowSymLinks
   AllowOverride All
  </Directory>
  ErrorLog /var/log/apache2/error.log
  LogLevel warn
  CustomLog /var/log/apache2/access.log combined
  RewriteEngine on
  RewriteCond %{SERVER_NAME} =www.netways.de [OR]
  RewriteCond %{SERVER_NAME} =netways.de
  RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,QSA,R=permanent]
 </VirtualHost>

Damit das Ganze nun auch funktioniert, muss natürlich der SSL-Vhost unter Port 443 erreichbar sein. Wie dieser initial erstellt wird, ist im Artikel SSL-Zertifikat einbinden beschrieben.
Übrigens: wer Let’s Encrypt verwendet, wird im Wizard gleich gefragt, ob SSL forciert werden soll. Der Wizard übernimmt dann die oben gezeigten Schritte. Wie man Let’s Encrypt einsetzt, haben wir natürlich auch schon einmal beschrieben. Damit später keine Seitenbesucher verloren gehen, sollte der HTTP-Vhost, der auf Port 80 läuft, nicht abgeschaltet werden. Die Verbindung ist mit dieser Maßnahme sicher und alle Besucher werden auf https umgeleitet.
Wer damit gar nichts zu tun haben will, und trotzdem stets auf der sicheren Seite sein will, der kann natürlich seine Seite auch bei NETWAYS im Managed Hosting betreuen lassen. Hier kümmern wir uns darum.
In den anderen (teilweise noch kommenden) Blogposts zum Thema SSL leicht gemacht geht es um:

Reminder für das Puppet Webinar – Windows Configuration Management

puppet Heute will ich noch mal auf das Webinar zum Thema Puppet: Windows Configuration Management am Freitag, den 12.12.2014 um 10:30 Uhr hinweisen. Gemeinsam mit Dirk werde ich demonstrieren, wie man Windows-Systeme mit Puppet deployen und konfigurieren kann.
Wer hieran teilnemhen möchte, kann sich natürlich gerne registrieren.
Um die Zeit zu überbrücken, kann man sich auch gerne die Webinar-Videos in unserem Webinar-Archiv anschauen.
Bis Freitag!

Christian Stein
Christian Stein
Manager Sales

Christian kommt ursprünglich aus der Personalberatungsbranche, wo er aber schon immer auf den IT Bereich spezialisiert war. Bei NETWAYS arbeitet er als Manager Sales und berät unsere Kunden in der vertrieblichen Phase rund um das Thema Monitoring. Gemeinsam mit Georg hat er sich Mitte 2012 auch an unserem Hardware-Shop "vergangen".

Config-Probleme mit Icinga 2 untersuchen

Um Konfigurationsfehler bei Icinga 2 in Zukunft noch einfacher untersuchen zu können, wird es in der nächste Woche erscheinenden Version 2.1 ein neues Tool geben:

# icinga2-list-objects
Object 'api' of type 'ApiListener':
  * templates = ['api']
    % modified in /etc/icinga2/features-enabled/api.conf, lines 5:1-11:1
  * bind_port = '5665'
    % modified in /etc/icinga2/features-enabled/api.conf, lines 10:3-10:20
  * __name = 'api'
  * ca_path = '/etc/icinga2/pki/ca.crt'
    % modified in /etc/icinga2/features-enabled/api.conf, lines 8:3-8:46
  * cert_path = '/etc/icinga2/pki/ztv.beutner.name.crt'
    % modified in /etc/icinga2/features-enabled/api.conf, lines 6:3-6:62
  * type = 'ApiListener'
  * key_path = '/etc/icinga2/pki/ztv.beutner.name.key'
    % modified in /etc/icinga2/features-enabled/api.conf, lines 7:3-7:61
[...]

Zunächst einmal listet icinga2-list-objects alle in den Konfigurationsdateien definierten Objekte auf. Auch Objekte, die mit „apply“ erstellt wurden, sind in dieser Liste enthalten, wodurch sich mit wenig Aufwand prüfen lässt, ob „apply“-Regeln so funktionieren, wie man es sich vorstellt.
Zusätzlich werden zu jedem Objekt die Attribute inkl. deren Werte angezeigt. Zu jedem Attribut wird außerdem mit angegeben, an welchen Stellen in der Konfiguration es gesetzt bzw. überschrieben wurde.
Im Troubleshooting-Guide werden noch weitere Tipps beschrieben, wie Config-Fehler erkannt und behoben werden können.