cancel
Showing results for 
Search instead for 
Did you mean: 

Use a client cert to perform a healthcheck

SOLVED
mgyles
Not applicable

Use a client cert to perform a healthcheck

We have many backend servers that present a "choose a digital certificate" box/prompt to the client before presenting a page. I would like to set up a monitor that could use that same process to determine if a node is alive or not. The perl scripts look promising... any suggestions, canned scripts you could point me to?

1 ACCEPTED SOLUTION

Accepted Solutions
owen
Frequent Contributor

Re: Use a client cert to perform a healthcheck

Response from Michael Granzow, Riverbed Technology

The standard monitors do not support client certificates, unfortunately.

As part of the traffic manager installation, you can find a command-line HTTP client in

$ZEUSHOME/admin/bin/httpclient

This tool also supports HTTPS and can be told to present a certificate should the server ask for one.

I've written a small wrapper around this program that can be used as a monitor of type 'external program', see below. Please download the file and save it on your computer under the name 'client_cert'.

The most convenient way to install it into your system is to use 'zcli'. Create a file called 'zcli_commands' with the necessary commands, like this:

   1. Catalog.Monitor.uploadMonitorProgram client_cert client_cert
   2. Conf.Extra.uploadFile client_cert.private ~/certs/client_cert.private
   3. Conf.Extra.uploadFile client_cert.public  ~/certs/client_cert.public
   4. Catalog.Monitor.addMonitors client_cert
   5. Catalog.Monitor.setType  client_cert program
   6. Catalog.Monitor.setProgram client_cert client_cert
   7. Catalog.Monitor.addProgramArguments   client_cert {description:"The certificate to use", name: "cert", value:"zxtm/conf/extra/client_cert.public"}
   8. Catalog.Monitor.addProgramArguments   client_cert {description:"The private key",name:"key",value:"zxtm/conf/extra/client_cert.private"}
   9. Catalog.Monitor.addProgramArguments   client_cert {description:"The Host header", name:"hostheader", value:"my.domain.com"}

This assumes that the certificate and corresponding private key you want to use are located in certs/client_cert.public and certs/client_cert.private under your home directory.

Obviously you'll have to replace 'my.domain.com' with the host header your web servers expect.

Then invoke zcli:

# $ZEUSHOME/zxtm/bin/zcli<zcli_commands

Now you have to make the installed program executable:

# chmod +x $ZEUSHOME/zxtm/conf/scripts/client_cert

and you should be able to use your new monitor with your pools. If you only want to consider certain http response codes successful, you can add another argument to the program, 'responsecode'.

This is the program (similar to dns.pl that comes with the software):

   1. #!/bin/sh
   2. # Bootstrap into the version of perl provided by Zeus
   3. exec $ZEUSHOME/perl/miniperl -wx $0 ${1+"[email protected]"}
   4.  if0;
   5. # -*- perl -*-
   6. #!/usr/bin/perl
   7. #line9
   8. # This monitor will contact an https server, and
   9. # provide an ssl client cert during the handshake if
  10. # the server requests it.  The program then checks
  11. # for a valid HTTP response and optionally for
  12. # certain response codes (regex).
  13. BEGIN{ unshift @INC,"$ENV{ZEUSHOME}/zxtm/lib/perl",
  14.                       "$ENV{ZEUSHOME}/zxtmadmin/lib/perl";}
  15. use Zeus::ZXTM::Monitor qw(ParseArgumentsMonitorWorkedMonitorFailedLog);
  16. # Process the arguments
  17. my%args =ParseArguments();
  18. if(! $args{ipaddr}){
  19.    MonitorFailed("No 'ipaddr' to contact specified");
  20. }
  21. my $ipaddr = $args{ipaddr};
  22. my $cmd ="$ENV{ZEUSHOME}/admin/bin/httpclient ";
  23. if(defined( $args{hostheader})){
  24.    $cmd .="--hostheader=$args{hostheader} ";
  25. }
  26. if(defined( $args{cert})&&defined( $args{key})){
  27.    $cmd .="--cert=$args{cert} --key=$args{key} ";
  28. }
  29. if( $ipaddr =~/:/){# handle IPv6 addresses
  30.    $cmd .="
https://[${ipaddr}]";
  31. }else{
  32.    $cmd .="
https://${ipaddr}";
  33. }
  34. if(defined( $args{port})){
  35.    $cmd .=":$args{port}/";
  36. }else{
  37.    # just slap on a slash
  38.    $cmd .='/';
  39. }
  40. Log("Running $cmd");
  41. # Now run the httpclient program
  42. open( PROG,"$cmd  2>&1 |");
  43. my $response ='';
  44. while( <PROG> ){
  45.    $response .= $_;
  46. }
  47. if(! close PROG ){
  48.    MonitorFailed("httpclient failed: $response")if $?;
  49.    MonitorFailed("$!")      if $!;
  50.    MonitorFailed("Unknown error");
  51. }
  52. Log("Output: $response");
  53. if( $response !~/^HTTP\/\d\.\d\s+(\d+)/){
  54.    my $idx = index( $response,"\n");
  55.    my $firstline = substr( $response,0,($idx >0)?$idx:15);
  56.    $firstline =~ s/\r$//;
  57.    MonitorFailed("HTTP request failed: first line was '$firstline'");
  58. }
  59. if(defined( $args{responsecode})){
  60.    if( $1 !~/$args{responsecode}/){
  61.       MonitorFailed("HTTP request failed, expected '$args{responsecode}', got '$1'");
  62.    }
  63. }
  64. MonitorWorked();

View solution in original post

3 REPLIES 3
owen
Frequent Contributor

Re: Use a client cert to perform a healthcheck

Response from Michael Granzow, Riverbed Technology

The standard monitors do not support client certificates, unfortunately.

As part of the traffic manager installation, you can find a command-line HTTP client in

$ZEUSHOME/admin/bin/httpclient

This tool also supports HTTPS and can be told to present a certificate should the server ask for one.

I've written a small wrapper around this program that can be used as a monitor of type 'external program', see below. Please download the file and save it on your computer under the name 'client_cert'.

The most convenient way to install it into your system is to use 'zcli'. Create a file called 'zcli_commands' with the necessary commands, like this:

   1. Catalog.Monitor.uploadMonitorProgram client_cert client_cert
   2. Conf.Extra.uploadFile client_cert.private ~/certs/client_cert.private
   3. Conf.Extra.uploadFile client_cert.public  ~/certs/client_cert.public
   4. Catalog.Monitor.addMonitors client_cert
   5. Catalog.Monitor.setType  client_cert program
   6. Catalog.Monitor.setProgram client_cert client_cert
   7. Catalog.Monitor.addProgramArguments   client_cert {description:"The certificate to use", name: "cert", value:"zxtm/conf/extra/client_cert.public"}
   8. Catalog.Monitor.addProgramArguments   client_cert {description:"The private key",name:"key",value:"zxtm/conf/extra/client_cert.private"}
   9. Catalog.Monitor.addProgramArguments   client_cert {description:"The Host header", name:"hostheader", value:"my.domain.com"}

This assumes that the certificate and corresponding private key you want to use are located in certs/client_cert.public and certs/client_cert.private under your home directory.

Obviously you'll have to replace 'my.domain.com' with the host header your web servers expect.

Then invoke zcli:

# $ZEUSHOME/zxtm/bin/zcli<zcli_commands

Now you have to make the installed program executable:

# chmod +x $ZEUSHOME/zxtm/conf/scripts/client_cert

and you should be able to use your new monitor with your pools. If you only want to consider certain http response codes successful, you can add another argument to the program, 'responsecode'.

This is the program (similar to dns.pl that comes with the software):

   1. #!/bin/sh
   2. # Bootstrap into the version of perl provided by Zeus
   3. exec $ZEUSHOME/perl/miniperl -wx $0 ${1+"[email protected]"}
   4.  if0;
   5. # -*- perl -*-
   6. #!/usr/bin/perl
   7. #line9
   8. # This monitor will contact an https server, and
   9. # provide an ssl client cert during the handshake if
  10. # the server requests it.  The program then checks
  11. # for a valid HTTP response and optionally for
  12. # certain response codes (regex).
  13. BEGIN{ unshift @INC,"$ENV{ZEUSHOME}/zxtm/lib/perl",
  14.                       "$ENV{ZEUSHOME}/zxtmadmin/lib/perl";}
  15. use Zeus::ZXTM::Monitor qw(ParseArgumentsMonitorWorkedMonitorFailedLog);
  16. # Process the arguments
  17. my%args =ParseArguments();
  18. if(! $args{ipaddr}){
  19.    MonitorFailed("No 'ipaddr' to contact specified");
  20. }
  21. my $ipaddr = $args{ipaddr};
  22. my $cmd ="$ENV{ZEUSHOME}/admin/bin/httpclient ";
  23. if(defined( $args{hostheader})){
  24.    $cmd .="--hostheader=$args{hostheader} ";
  25. }
  26. if(defined( $args{cert})&&defined( $args{key})){
  27.    $cmd .="--cert=$args{cert} --key=$args{key} ";
  28. }
  29. if( $ipaddr =~/:/){# handle IPv6 addresses
  30.    $cmd .="
https://[${ipaddr}]";
  31. }else{
  32.    $cmd .="
https://${ipaddr}";
  33. }
  34. if(defined( $args{port})){
  35.    $cmd .=":$args{port}/";
  36. }else{
  37.    # just slap on a slash
  38.    $cmd .='/';
  39. }
  40. Log("Running $cmd");
  41. # Now run the httpclient program
  42. open( PROG,"$cmd  2>&1 |");
  43. my $response ='';
  44. while( <PROG> ){
  45.    $response .= $_;
  46. }
  47. if(! close PROG ){
  48.    MonitorFailed("httpclient failed: $response")if $?;
  49.    MonitorFailed("$!")      if $!;
  50.    MonitorFailed("Unknown error");
  51. }
  52. Log("Output: $response");
  53. if( $response !~/^HTTP\/\d\.\d\s+(\d+)/){
  54.    my $idx = index( $response,"\n");
  55.    my $firstline = substr( $response,0,($idx >0)?$idx:15);
  56.    $firstline =~ s/\r$//;
  57.    MonitorFailed("HTTP request failed: first line was '$firstline'");
  58. }
  59. if(defined( $args{responsecode})){
  60.    if( $1 !~/$args{responsecode}/){
  61.       MonitorFailed("HTTP request failed, expected '$args{responsecode}', got '$1'");
  62.    }
  63. }
  64. MonitorWorked();

nicholas_2
Occasional Contributor

Re: Use a client cert to perform a healthcheck

Hi,

found mistake in script

Wrong:

  44. while(){

  45.    $response .= $_;

  46. }

Correct:

  44. while(<PROG>){

  45.    $response .= $_;

  46. }

owen
Frequent Contributor

Re: Re: Use a client cert to perform a healthcheck

Thanks - I've updated the script above with your correction.  Regards

Owen