Icinga2 Powershell Framework [Feedback]

I just took a look at the Icinga2 Powershell framework and it looks very nice and polished.

Played a little bit with the agent installer and liked the service-permission functions a lot :slight_smile:

At the moment I’am using the director powershell modul to deploy new agents. Just from reading the code, it looks like its not possible to add Hosts directly into the director witch custom variables etc. like it is with the powershell module and the “-DirectorHostObject $json” parameter. Is this true? If so, is this planed?

Will test some more features like the powershell service and report back with some feedback. For now everything looks awesome. I Like that there are so much small and useful functions that all adds up in the nodewizard script.

Best regards,
Rafael

So after a while of testing the Framework, i would like to give some feedback:

First of all, if everything is setup correctly it works very well.

The way of executing Start-IcingaAgentInstallWizard is a little complicate, because you nearly need to configure every switch. My command is 627 Chars long. A Good idea would be to add some switches like -CAProxy to auto set some other parameters to the correct value.

The -AllowConnection" switch has a strange name. After reading to the code it looks like it is only used for define if you can reach the master f.e. for ca signing, but as I’am configuring the agent here, I expect that “Allow connections” are from the agent point of view. So f.e. -ParentReachable, -CAReachabe or -ConnectionPossible would be a better name for it.

Also the script will not work on Powershell 4.0. To make it backward compatible I changes these 3 files:

  1. Get-IcingaUSerSID.psm1 will throw this error on PS4.0:
Method invocation failed because [System.Security.Principal.NTAccount] does not contain a method named 'New'.

This can be solved by changing line 20 from

$NTUser   = [System.Security.Principal.NTAccount]::New($Domain, $Username);

to

$NTUser = new-object system.security.principal.NTAccount($Domain, $Username);
  1. Getter and setter for Service Permissions [get|set]-IcingaAgentServicePermission.psm1:

Replace

$SystemPermissions = New-TemporaryFile;

with

if (Get-Command New-TemporaryFile -errorAction SilentlyContinue | out-null) {
        $SystemPermissions = New-TemporaryFile;
    } else {
        $randomNumber =  Get-Random -Maximum 99999;
        $SystemPermissions =  New-Item -Type File -Path $Env:Temp\tmp$randomNumber.tmp;
    }

because function New-TemporaryFile is new in 5.x

Thats it for now :slight_smile:

I’d like to know some technical details especially the communication path. As far I remember my tests with a very early version some month ago, the communication was from Icinga 2 Powershell Module to master only but not to satellites. Is this still in place?

And what about connection security? Is it similar or even identical to the cluster protocol?

If you @unic cannot answer my questions, hopefully @cstein can jump in.

Hi Roland,

That depends of how you configure it. I’am using the ca proxy feature, so the script does not need to reach any server at all.

As soon as I deploy the Host configuration with the director, the master or satellite will connect to the agent and the host will appear in ‘icinga2 ca list’ with his csr. After it is signed on the master, I need to restart the agent once (looks like there is a bug) because the signed certificate does not work before the Agent is restarted.

Additional my deploymentscript will check some information on the windows server and auto create the host with with the director api on a special port, where only some requests are allowed. For this to work, this port needs to be reachable for every server. This way the windows admin can add there hosts completly autonomous (sadly, this restart thing is in the way at the moment :)) But this has nothing to do with the framework, as it looks like its not possible to add custom vars with the self service api (as far as i know).

To clarify: Icinga Powershell Module and Powershell framework are completely different things.

More information about the framework can be found here: A modest attempt to Monitor Windows Service in services.msc

1 Like

Hello and thank you for the feedback :slight_smile:

I will apply the proposed changes - somehow this slipped through. The Wizard itself turned out to “explode” a little during the implementation, because of all the different possibilities. I’m open for improvements in this case.

@rsx: If the script is directly copied from the Icinga Director (the old module), the endpoints were always fixed to the master. In general the old module as well as the new framework will support a parent Icinga 2 satellite as certificate endpoint (or for CA-Proxy handling). The framework does many things a little different in an improved way. I beliebe all three possibilities to generate certificates should be supported

@unic: At the moment a direct authentication to the Director, like the old module supported, is not yet implemented. Depending on the requirements we could add support for this or maybe design a different, more “secure” way to prevent having to share Director credentials over scripts. What do you think?

I created some issues for the mentioned topics
Get-IcingaUserSID
New-TemporaryFile

Thanks for the reports !

1 Like

My question was mainly about the check results and CA-Proxy handling is about certificate staff only, right?

Yes this is true - CA-Proxy is only about certificates.
What do you mean wtih check-results? Are you refering to the old module, sending data to Icinga Web 2?

If this is the case, this is no longer part of this module. The framework provides a toolset of functions and components to write PowerShell plugins more easily and to allow a wider integration.

Monitoring, installation, configuration and updates are all combined now.

1 Like

The icinga Windows Agent communicates with its parent via the cluster protocol (means JSON-RPC and TLS secured over port 5665/tcp by default). How does the new framework communicates with its parent?

The framework still installs the Icinga Windows agent, configures it and runs the CLI commands to send certificate signing requests. The cluster communication is done via Icinga agent and TLS/JSON-RPC, as you are used to it.

1 Like

Hi and thanks for your reply and fast fixing of these problems.

I though about a -silent switch where every arguments that is not given is set to “false” silently.

I would like a more secure way :slight_smile: I have the same problem with the password for the Agent-Service. I haven’t found a way yet, to encrypt the password in a way, that the adminuser can decrypt it at runtime on every Machine.

My quick and dirty function for adding the Hosts with the Director:

#API URL
[string]$DirectorUrl      = "https://$($DirectorServer):10443/icingaweb2/director"

$directorUser = "User"
$directorPass = "Passwor[d|t]"

#Convert Credentials to Base64 for URL Header
$bytes = [System.Text.Encoding]::UTF8.GetBytes(('{0}:{1}' -f $directorUser , $directorPass))
$authorization = 'Basic {0}' -f ([Convert]::ToBase64String($bytes))

#Create a new Header
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
  
#Add converted Authorization
$headers.Add("Authorization", "$authorization")
#Add Application type
$headers.Add('Accept','application/json')


function Add-IcingaHost($hostname, $address, [array]$templates, $displayname, [hashtable]$vars, [switch]$simulate, [switch]$skipError) {
  if (-not $address -or -not $hostname -or -not $templates) {
    write-host "At least these fields are required: -templates $templates -address $address -hostname $hostname"
    break
  }
  $hostObj = New-Object -TypeName psobject
  $hostObj | Add-Member -MemberType NoteProperty -Name object_name -Value "$hostname"
  $hostObj | Add-Member -MemberType NoteProperty -Name object_type -Value "object"
  $hostObj | Add-Member -MemberType NoteProperty -Name address -Value "$address"
  $hostObj | Add-Member -MemberType NoteProperty -Name imports -Value $templates
  if ($displayname) { $hostObject | Add-Member -MemberType NoteProperty -Name displayname -Value "$displayname" }
  if ($vars) {
    $hostObj | Add-Member -MemberType NoteProperty -Name vars -Value $vars
  }

  $body = $hostObj | ConvertTo-Json 
  if ($simulate) {
    write-host "Body:" -ForegroundColor Green
    write-host $body 
  } else {
    try {
      Invoke-RestMethod -Method POST -Headers $headers  -Uri "$DirectorURL/host" -Body $body
    } catch {
      #$_.Exception #.Message
      write-host $_ -ForegroundColor Red
      write-host "URI: $BaseURL/host"
      write-host "body:`n$body"
      if (!($skipError)) {
        $answer = read-host "Continue? [y/n]?"
        if ( $answer -ne "y" ) { exit }
      }
    }
  }
}

$templates =   @( "WINDOWS SERVER AGENT", "$SatelliteTemplate" )
$vars = @{type="vm"}
$vars.Add("os", $os)
$vars.Add("windows_disks", $disklist)

Add-IcingaHost  -templates $templates -hostname "$hostname" -address "$hostname"  -vars $vars #-simulate

1 Like

You could also the the -Credential argument for the Invoke-RestMethod and use Get-Credential to receive the User and and the Password as SecureString.

I’m however not certain on how this will result with Powershell remote execution tasks ouf of the box.

Hi,

I tried it with the -credentials first, but with that i could not authenticate with the director.
Thats why I created the ugly way :slight_smile: @cstein: Do you have an example snipped with that working?

I’m not sure whether to post here or open a new thread. So fell free to correct my post accordingly.

First, I could not find any technical documentation so it’s like reverse engineering. I’ve realized the framework tries to download from the internet (which is not allowed in my test environment). I’d assume this will not happen it I’ve a custom repository (for which I’d need to know how to prepare it).

Due to the failing download the script should not continue:

PS C:\Users\Administrator> Start-IcingaAgentInstallWizard
Do you want to use the Icinga Director Self-Service API? (Y/n):
Please specify the Url pointing to your Icinga Director: http://192.168.53.210/icingaweb2/director/
Do you want to manually override arguments provided by the Director API? (y/N):
Please enter your Self-Service API key: **************
Using hostname "IcingaAgentTest.EM.LAN" for the Icinga 2 Agent configuration
Is your public Icinga 2 CA (ca.crt) available on a local, network or web share? (Y/n): n
Do you want to install the Icinga Plugins? (Y/n):
Do you provide a custom repository for the Icinga Plugins? (y/N):
Which version to you want to install? (snapshot/stable) (Default: "stable"):
Invoke-WebRequest : Unable to connect to the remote server
At C:\Program
Files\WindowsPowerShell\Modules\icinga-powershell-framework\lib\core\framework\Install-IcingaFrameworkPlugins.psm1:16
char:35
+                 $LatestRelease = (Invoke-WebRequest -Uri 'https://github.com/Ici ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-WebRequest], WebExc
   eption
    + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeWebRequestCommand

You cannot call a method on a null-valued expression.
At C:\Program
Files\WindowsPowerShell\Modules\icinga-powershell-framework\lib\core\framework\Install-IcingaFrameworkPlugins.psm1:17
char:17
+                 $PluginsUrl    = $LatestRelease.Replace('/releases/tag/', '/arch ...
+                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull

Downloading Icinga Plugins into "C:\Users\ADMINI~1\AppData\Local\Temp\2\icinga-powershell-plugins.zip"
Invoke-WebRequest : Invalid URI: The hostname could not be parsed.
At C:\Program
Files\WindowsPowerShell\Modules\icinga-powershell-framework\lib\core\framework\Install-IcingaFrameworkPlugins.psm1:39
char:5
+     Invoke-WebRequest -UseBasicParsing -Uri $PluginsUrl -OutFile $DownloadPath;
+     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Invoke-WebRequest], UriFormatException
    + FullyQualifiedErrorId : System.UriFormatException,Microsoft.PowerShell.Commands.InvokeWebRequestCommand

Installing plugins into "C:\Program Files\WindowsPowerShell\Modules\"
The path to the zip archive or the destination path do not exist
No update package could be found.
Do you want to install the PowerShell Framework as a Service? (Y/n):
Do you provide a custom source of the service binary? (y/N):
Invoke-WebRequest : Unable to connect to the remote server
At C:\Program Files\WindowsPowerShell\Modules\icinga-powershell-framework\lib\core\framework\Get-IcingaFrameworkService
Binary.psm1:12 char:37
+             $LatestRelease       = (Invoke-WebRequest -Uri 'https://github.com/I ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-WebRequest], WebExc
   eption
    + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeWebRequestCommand

You cannot call a method on a null-valued expression.
At C:\Program Files\WindowsPowerShell\Modules\icinga-powershell-framework\lib\core\framework\Get-IcingaFrameworkService
Binary.psm1:13 char:13
+             $FrameworkServiceUrl = $LatestRelease.Replace('/tag/', '/download/') ...
+             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull

Please enter the path you wish to install the service to (Default: "C:\Program Files\icinga-framework-service\"):

Specifying a wrong url should also be handled:

PS C:\Users\Administrator> Start-IcingaAgentInstallWizard
Do you want to use the Icinga Director Self-Service API? (Y/n):
Please specify the Url pointing to your Icinga Director: http://192.168.53.210
Do you want to manually override arguments provided by the Director API? (y/N):
Please enter your Self-Service API key: ***************
Invoke-WebRequest : Not Found
The requested URL was not found on this server.
Apache/2.4.29 (Ubuntu) Server at 192.168.53.210 Port 80
At C:\Program
Files\WindowsPowerShell\Modules\icinga-powershell-framework\lib\apis\Get-IcingaDirectorSelfServiceConfig.psm1:20
char:17
+     $response = Invoke-WebRequest -Uri $EndpointUrl -UseBasicParsing -Headers @{ ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-WebRequest], WebExc
   eption
    + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeWebRequestCommand
ScriptHalted
At C:\Program
Files\WindowsPowerShell\Modules\icinga-powershell-framework\lib\apis\Get-IcingaDirectorSelfServiceConfig.psm1:23 char:9
+         throw $response.Content;
+         ~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : OperationStopped: (:) [], RuntimeException
    + FullyQualifiedErrorId : ScriptHalted

In case it’s relevant: Windows 2012 R2:

PS C:\Users\Administrator> $PSVersionTable

Name                           Value
----                           -----
PSVersion                      4.0
WSManStackVersion              3.0
SerializationVersion           1.1.0.1
CLRVersion                     4.0.30319.42000
BuildVersion                   6.3.9600.19170
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0}
PSRemotingProtocolVersion      2.2

Hmm, it looks like http is not a valid repository option or the files there are not as expected:

Users\Administrator> Start-IcingaAgentInstallWizard
Do you want to use the Icinga Director Self-Service API? (Y/n):
Please specify the Url pointing to your Icinga Director: http://192.168.53.210/icingaweb2/director/
Do you want to manually override arguments provided by the Director API? (y/N):
Using hostname "IcingaAgentTest.EM.LAN" for the Icinga 2 Agent configuration
Is your public Icinga 2 CA (ca.crt) available on a local, network or web share? (Y/n): n
Do you want to install the Icinga Plugins? (Y/n):
Do you provide a custom repository for the Icinga Plugins? (y/N): y
Please enter the full path to your Icinga Plugin repository: http://192.168.53.210/download/
Downloading Icinga Plugins into "C:\Users\ADMINI~1\AppData\Local\Temp\2\icinga-powershell-plugins.zip"
Installing plugins into "C:\Program Files\WindowsPowerShell\Modules\"
Exception calling "ExtractToDirectory" with "2" argument(s): "End of Central Directory record could not be found."
At C:\Program
Files\WindowsPowerShell\Modules\icinga-powershell-framework\lib\core\framework\Expand-IcingaZipArchive.psm1:16 char:9
+         [System.IO.Compression.ZipFile]::ExtractToDirectory($Path, $Destination) ...
+         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : InvalidDataException

Ok, got it myself. For custom repositories the full url including file name needs to be entered.

However, I’d suggest to add more error handling at least for the described issues.

Mind creating GitHub issues for better tracking?

1 Like

Uff, sure when I find time. Hopefully @cstein will not kill me.

And another issue: The api key changed (for what ever reason!? I’ve changed agent settings at the director, does this changes the key?) and now I’m getting:

PS C:\Users\Administrator> Start-IcingaAgentInstallWizard
o you want to use the Icinga Director Self-Service API? (Y/n):
lease specify the Url pointing to your Icinga Director: http://192.168.53.210/icingaweb2/director/
o you want to manually override arguments provided by the Director API? (y/N):
cinga Director Self-Service has thrown an error: Got invalid API key "*******************"
t C:\Program
iles\WindowsPowerShell\Modules\icinga-powershell-framework\lib\apis\Get-IcingaDirectorSelfServiceConfig.psm1:29 char:9
         throw 'Icinga Director Self-Service has thrown an error: ' + $JsonConten ...
         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   + CategoryInfo          : OperationStopped: (Icinga Director...*****************":String) [], RuntimeException
   + FullyQualifiedErrorId : Icinga Director Self-Service has thrown an error: Got invalid API key "***************************"

It looks like it is stored somewhere? But where?

You can also use a local path here like -PackageSource "c:\testdeploy" then it will try to find the msi with the version given with -AgentVersion “2.11.2” there.

The first url was about the plugins, the second about the service.